[libvirt] Add support for (qcow*) volume encryption (v3)

Hello, the following patches add full support for qcow/qcow2 volume encryption, assuming a client that supports it. (Main changes since the previous version: * Significantly change the internal API, basing it on virSecretPtr instead of (virConnectPtr, secret_id); details in patch 1 * Make virsh commands more similar to the existing commands * Remove <encryption format='unencrypted'/> * Rename "secret_id" to "uuid" in the XML and API * Use "unsigned char *" for secret value See the specific patch change logs for more details; patches without change logs are unchanged.) New XML tags are defined to represent encryption parameters (currently format and passphrase, more can be added in the future), e.g. <encryption format='qcow'> <secret type='passphrase' uuid='724d95f2-0ed2-6ff9-84d0-0f3d1618428d'/> </encryption> The <encryption> tag can be added to a <volume> node passed to virStorageVolCreateXML() to create an encrypted volume, or to a <disk> node inside a <domain> to specify what encryption parameters to use for a domain. uuid above refers to a separately-managed secret, which was created using virSecretDefineXML() and set using virSecretSetValue(). Other properties of the secret can be managed using an XML representation. Detailed documentation of the formats and features is inside the patches.

This patch adds a "secret" as a separately managed object, using a special-purpose API to transfer the secret values between nodes and libvirt users. Rather than add explicit accessors for attributes of secrets, and hard-code the "secrets are related to storage volumes" association in the API, the API uses XML to manipulate the association as well as other attributes, similarly to other areas of libvirt. The user can set attributes of the secret using XML, e.g. <secret ephemeral='no' private='yes'> <uuid>b8eecf55-798e-4db7-b2dd-025b0cf08a36</uuid> <volume>/var/lib/libvirt/images/mail.img</volume> <description>LUKS passphrase for our mail server</description> </secret> If <uuid/> is not specified, it is chosen automatically. The secret value can be either generated and stored by libvirt during volume creation, or supplied by the user using virSecretSetValue(). A simple API is provided for enumeration of all secrets. Very large deployments will manage secret IDs automatically, so it is probably not necessary to provide a specialized lookup function (allowing the volume key -> secret ID lookup in less than O(number of secrets)). These functions can eventually be added later. Changes since the second submission: - Changed API to revolve around a virSecretPtr. The operations are now: virSecretGetConnect virConnectNumOfSecrets virConnectListSecrets virSecretLookupByUUIDString virSecretDefineXML virSecretGetUUIDString virSecretGetXMLDesc virSecretSetValue virSecretGetValue virSecretUndefine virSecretRef virSecretFree - Use an optional <uuid/> element inside <secret/> to pre-specify an UUID in virSecretDefineXML() (default is to choose an UUID automatically) - s/secret_id/uuid/g - use "unsigned char *" for secret value - Use "Secret XML" instead of "Secret attributes XML" in the HTML documentation now that the XML contains the UUID as well. --- docs/format.html | 4 + docs/formatcaps.html | 4 + docs/formatdomain.html | 4 + docs/formatnetwork.html | 4 + docs/formatnode.html | 4 + docs/formatsecret.html | 170 ++++++++++++++++++++++++++++++++++++++++++ docs/formatsecret.html.in | 52 +++++++++++++ docs/formatstorage.html | 4 + docs/schemas/Makefile.am | 1 + docs/schemas/secret.rng | 44 +++++++++++ docs/sitemap.html | 3 + docs/sitemap.html.in | 4 + include/libvirt/libvirt.h | 34 +++++++++ include/libvirt/libvirt.h.in | 34 +++++++++ src/libvirt_public.syms | 16 ++++ 15 files changed, 382 insertions(+), 0 deletions(-) create mode 100644 docs/formatsecret.html create mode 100644 docs/formatsecret.html.in create mode 100644 docs/schemas/secret.rng diff --git a/docs/format.html b/docs/format.html index e97d0e7..3c20b5f 100644 --- a/docs/format.html +++ b/docs/format.html @@ -70,6 +70,10 @@ <div> <a title="The host device XML format" class="inactive" href="formatnode.html">Node Devices</a> </div> + </li><li> + <div> + <a title="The secret XML format" class="inactive" href="formatsecret.html">Secrets</a> + </div> </li></ul> </div> </li><li> diff --git a/docs/formatcaps.html b/docs/formatcaps.html index 5b20aac..5f2bc72 100644 --- a/docs/formatcaps.html +++ b/docs/formatcaps.html @@ -70,6 +70,10 @@ <div> <a title="The host device XML format" class="inactive" href="formatnode.html">Node Devices</a> </div> + </li><li> + <div> + <a title="The secret XML format" class="inactive" href="formatsecret.html">Secrets</a> + </div> </li></ul> </div> </li><li> diff --git a/docs/formatdomain.html b/docs/formatdomain.html index 5415200..6b655ad 100644 --- a/docs/formatdomain.html +++ b/docs/formatdomain.html @@ -70,6 +70,10 @@ <div> <a title="The host device XML format" class="inactive" href="formatnode.html">Node Devices</a> </div> + </li><li> + <div> + <a title="The secret XML format" class="inactive" href="formatsecret.html">Secrets</a> + </div> </li></ul> </div> </li><li> diff --git a/docs/formatnetwork.html b/docs/formatnetwork.html index 0b25a0b..72a3cda 100644 --- a/docs/formatnetwork.html +++ b/docs/formatnetwork.html @@ -70,6 +70,10 @@ <div> <a title="The host device XML format" class="inactive" href="formatnode.html">Node Devices</a> </div> + </li><li> + <div> + <a title="The secret XML format" class="inactive" href="formatsecret.html">Secrets</a> + </div> </li></ul> </div> </li><li> diff --git a/docs/formatnode.html b/docs/formatnode.html index 4d30b0c..516c27b 100644 --- a/docs/formatnode.html +++ b/docs/formatnode.html @@ -70,6 +70,10 @@ <div> <span class="active">Node Devices</span> </div> + </li><li> + <div> + <a title="The secret XML format" class="inactive" href="formatsecret.html">Secrets</a> + </div> </li></ul> </div> </li><li> diff --git a/docs/formatsecret.html b/docs/formatsecret.html new file mode 100644 index 0000000..998e874 --- /dev/null +++ b/docs/formatsecret.html @@ -0,0 +1,170 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<!-- + This file is autogenerated from formatsecret.html.in + Do not edit this file. Changes will be lost. + --> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /> + <link rel="stylesheet" type="text/css" href="main.css" /> + <link rel="SHORTCUT ICON" href="32favicon.png" /> + <title>libvirt: Secret XML format</title> + <meta name="description" content="libvirt, virtualization, virtualization API" /> + </head> + <body> + <div id="header"> + <div id="headerLogo"></div> + <div id="headerSearch"> + <form action="search.php" enctype="application/x-www-form-urlencoded" method="get"><div> + <input id="query" name="query" type="text" size="12" value="" /> + <input id="submit" name="submit" type="submit" value="Search" /> + </div></form> + </div> + </div> + <div id="body"> + <div id="menu"> + <ul class="l0"><li> + <div> + <a title="Front page of the libvirt website" class="inactive" href="index.html">Home</a> + </div> + </li><li> + <div> + <a title="Details of new features and bugs fixed in each release" class="inactive" href="news.html">News</a> + </div> + </li><li> + <div> + <a title="Get the latest source releases, binary builds and get access to the source repository" class="inactive" href="downloads.html">Downloads</a> + </div> + </li><li> + <div> + <a title="Information for users, administrators and developers" class="active" href="docs.html">Documentation</a> + <ul class="l1"><li> + <div> + <a title="Information about deploying and using libvirt" class="inactive" href="deployment.html">Deployment</a> + </div> + </li><li> + <div> + <a title="Overview of the logical subsystems in the libvirt API" class="inactive" href="intro.html">Architecture</a> + </div> + </li><li> + <div> + <a title="Description of the XML formats used in libvirt" class="active" href="format.html">XML format</a> + <ul class="l2"><li> + <div> + <a title="The domain XML format" class="inactive" href="formatdomain.html">Domains</a> + </div> + </li><li> + <div> + <a title="The virtual network XML format" class="inactive" href="formatnetwork.html">Networks</a> + </div> + </li><li> + <div> + <a title="The storage pool and volume XML format" class="inactive" href="formatstorage.html">Storage</a> + </div> + </li><li> + <div> + <a title="The driver capabilities XML format" class="inactive" href="formatcaps.html">Capabilities</a> + </div> + </li><li> + <div> + <a title="The host device XML format" class="inactive" href="formatnode.html">Node Devices</a> + </div> + </li><li> + <div> + <span class="active">Secrets</span> + </div> + </li></ul> + </div> + </li><li> + <div> + <a title="Hypervisor specific driver information" class="inactive" href="drivers.html">Drivers</a> + </div> + </li><li> + <div> + <a title="Reference manual for the C public API" class="inactive" href="html/index.html">API reference</a> + </div> + </li><li> + <div> + <a title="Bindings of the libvirt API for other languages" class="inactive" href="bindings.html">Language bindings</a> + </div> + </li><li> + <div> + <a title="Working on the internals of libvirt API, driver and daemon code" class="inactive" href="internals.html">Internals</a> + </div> + </li></ul> + </div> + </li><li> + <div> + <a title="User contributed content" class="inactive" href="http://wiki.libvirt.org">Wiki</a> + </div> + </li><li> + <div> + <a title="Frequently asked questions" class="inactive" href="FAQ.html">FAQ</a> + </div> + </li><li> + <div> + <a title="How and where to report bugs and request features" class="inactive" href="bugs.html">Bug reports</a> + </div> + </li><li> + <div> + <a title="How to contact the developers via email and IRC" class="inactive" href="contact.html">Contact</a> + </div> + </li><li> + <div> + <a title="Miscellaneous links of interest related to libvirt" class="inactive" href="relatedlinks.html">Related Links</a> + </div> + </li><li> + <div> + <a title="Overview of all content on the website" class="inactive" href="sitemap.html">Sitemap</a> + </div> + </li></ul> + </div> + <div id="content"> + <h1>Secret XML format</h1> + <ul><li> + <a href="#SecretAttributes">Secret XML</a> + </li><li> + <a href="#example">Example</a> + </li></ul> + <h2> + <a name="SecretAttributes" id="SecretAttributes">Secret XML</a> + </h2> + <p> + Secrets stored by libvirt may have attributes associated with them, using + the <code>secret</code> element. The <code>secret</code> element has two + optional attributes, each with values '<code>yes</code>' and + '<code>no</code>', and defaulting to '<code>no</code>': + </p> + <dl><dt><code>ephemeral</code></dt><dd>This secret must only be kept in memory, never stored persistently. + </dd><dt><code>private</code></dt><dd>The value of the secret must not be revealed to any caller of libvirt, + nor to any other node. + </dd></dl> + <p> + The top-level <code>secret</code> element may contain the following + elements: + </p> + <dl><dt><code>uuid</code></dt><dd> + An unique identifier for this secret (not necessarily in the UUID + format). If omitted when defining a new secret, a random UUID is + generated. + </dd><dt><code>volume</code></dt><dd>Key of a volume this secret is associated with. It is safe to delete + the secret after the volume is deleted. + </dd><dt><code>description</code></dt><dd>A human-readable description of the purpose of the secret. + </dd></dl> + <h2> + <a name="example" id="example">Example</a> + </h2> + <pre> + <secret ephemeral='no' private='yes'> + <volume>/var/lib/libvirt/images/mail.img</volume> + <description>LUKS passphrase for the main hard drive of our mail server</description> + </secret></pre> + </div> + </div> + <div id="footer"> + <p id="sponsor"> + Sponsored by:<br /><a href="http://et.redhat.com/"><img src="et.png" alt="Project sponsored by Red Hat Emerging Technology" /></a></p> + </div> + </body> +</html> diff --git a/docs/formatsecret.html.in b/docs/formatsecret.html.in new file mode 100644 index 0000000..7471bf7 --- /dev/null +++ b/docs/formatsecret.html.in @@ -0,0 +1,52 @@ +<html> + <body> + <h1>Secret XML format</h1> + + <ul id="toc"></ul> + + <h2><a name="SecretAttributes">Secret XML</a></h2> + + <p> + Secrets stored by libvirt may have attributes associated with them, using + the <code>secret</code> element. The <code>secret</code> element has two + optional attributes, each with values '<code>yes</code>' and + '<code>no</code>', and defaulting to '<code>no</code>': + </p> + <dl> + <dt><code>ephemeral</code></dt> + <dd>This secret must only be kept in memory, never stored persistently. + </dd> + <dt><code>private</code></dt> + <dd>The value of the secret must not be revealed to any caller of libvirt, + nor to any other node. + </dd> + </dl> + <p> + The top-level <code>secret</code> element may contain the following + elements: + </p> + <dl> + <dt><code>uuid</code></dt> + <dd> + An unique identifier for this secret (not necessarily in the UUID + format). If omitted when defining a new secret, a random UUID is + generated. + </dd> + <dt><code>volume</code></dt> + <dd>Key of a volume this secret is associated with. It is safe to delete + the secret after the volume is deleted. + </dd> + <dt><code>description</code></dt> + <dd>A human-readable description of the purpose of the secret. + </dd> + </dl> + + <h2><a name="example">Example</a></h2> + + <pre> + <secret ephemeral='no' private='yes'> + <volume>/var/lib/libvirt/images/mail.img</volume> + <description>LUKS passphrase for the main hard drive of our mail server</description> + </secret></pre> + </body> +</html> diff --git a/docs/formatstorage.html b/docs/formatstorage.html index 91e63b4..02cbcac 100644 --- a/docs/formatstorage.html +++ b/docs/formatstorage.html @@ -70,6 +70,10 @@ <div> <a title="The host device XML format" class="inactive" href="formatnode.html">Node Devices</a> </div> + </li><li> + <div> + <a title="The secret XML format" class="inactive" href="formatsecret.html">Secrets</a> + </div> </li></ul> </div> </li><li> diff --git a/docs/schemas/Makefile.am b/docs/schemas/Makefile.am index ef41a63..a064518 100644 --- a/docs/schemas/Makefile.am +++ b/docs/schemas/Makefile.am @@ -5,6 +5,7 @@ schema_DATA = \ domain.rng \ interface.rng \ network.rng \ + secret.rng \ storagepool.rng \ storagevol.rng \ nodedev.rng \ diff --git a/docs/schemas/secret.rng b/docs/schemas/secret.rng new file mode 100644 index 0000000..05e04f2 --- /dev/null +++ b/docs/schemas/secret.rng @@ -0,0 +1,44 @@ +<!-- A Relax NG schema for the libvirt secret properties XML format --> +<grammar xmlns="http://relaxng.org/ns/structure/1.0"> + <start> + <ref name='secret'/> + </start> + + <define name='secret'> + <element name='secret'> + <optional> + <attribute name='ephemeral'> + <choice> + <value>yes</value> + <value>no</value> + </choice> + </attribute> + </optional> + <optional> + <attribute name='private'> + <choice> + <value>yes</value> + <value>no</value> + </choice> + </attribute> + </optional> + <interleave> + <optional> + <element name='uuid'> + <text/> + </element> + </optional> + <optional> + <element name='description'> + <text/> + </element> + </optional> + <optional> + <element name='volume'> + <text/> + </element> + </optional> + </interleave> + </element> + </define> +</grammar> diff --git a/docs/sitemap.html b/docs/sitemap.html index f79a533..901633d 100644 --- a/docs/sitemap.html +++ b/docs/sitemap.html @@ -141,6 +141,9 @@ </li><li> <a href="formatnode.html">Node Devices</a> <span>The host device XML format</span> + </li><li> + <a href="formatsecret.html">Secrets</a> + <span>The secret XML format</span> </li></ul></li><li> <a href="drivers.html">Drivers</a> <span>Hypervisor specific driver information</span> diff --git a/docs/sitemap.html.in b/docs/sitemap.html.in index 9589878..2ed25c6 100644 --- a/docs/sitemap.html.in +++ b/docs/sitemap.html.in @@ -106,6 +106,10 @@ <a href="formatnode.html">Node Devices</a> <span>The host device XML format</span> </li> + <li> + <a href="formatsecret.html">Secrets</a> + <span>The secret XML format</span> + </li> </ul> </li> <li> diff --git a/include/libvirt/libvirt.h b/include/libvirt/libvirt.h index 855f755..fd5a70f 100644 --- a/include/libvirt/libvirt.h +++ b/include/libvirt/libvirt.h @@ -1448,6 +1448,40 @@ void virEventRegisterImpl(virEventAddHandleFunc addHandle, virEventAddTimeoutFunc addTimeout, virEventUpdateTimeoutFunc updateTimeout, virEventRemoveTimeoutFunc removeTimeout); + +/* + * Secret manipulation API + */ + +/** + * virSecret: + * + * A virSecret stores a secret value (e.g. a passphrase or encryption key) + * and associated metadata. + */ +typedef struct _virSecret virSecret; +typedef virSecret *virSecretPtr; + +virConnectPtr virSecretGetConnect (virSecretPtr secret); +int virConnectNumOfSecrets (virConnectPtr conn); +int virConnectListSecrets (virConnectPtr conn, + char **uuids, + int maxuuids); +virSecretPtr virSecretLookupByUUIDString(virConnectPtr conn, + const char *uuid); +virSecretPtr virSecretDefineXML (virConnectPtr conn, + const char *xml); +char * virSecretGetUUIDString (virSecretPtr secret); +char * virSecretGetXMLDesc (virSecretPtr secret); +int virSecretSetValue (virSecretPtr secret, + const unsigned char *value, + size_t value_size); +unsigned char * virSecretGetValue (virSecretPtr secret, + size_t *value_size); +int virSecretUndefine (virSecretPtr secret); +int virSecretRef (virSecretPtr secret); +int virSecretFree (virSecretPtr secret); + #ifdef __cplusplus } #endif diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index e6536c7..2f7286b 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1448,6 +1448,40 @@ void virEventRegisterImpl(virEventAddHandleFunc addHandle, virEventAddTimeoutFunc addTimeout, virEventUpdateTimeoutFunc updateTimeout, virEventRemoveTimeoutFunc removeTimeout); + +/* + * Secret manipulation API + */ + +/** + * virSecret: + * + * A virSecret stores a secret value (e.g. a passphrase or encryption key) + * and associated metadata. + */ +typedef struct _virSecret virSecret; +typedef virSecret *virSecretPtr; + +virConnectPtr virSecretGetConnect (virSecretPtr secret); +int virConnectNumOfSecrets (virConnectPtr conn); +int virConnectListSecrets (virConnectPtr conn, + char **uuids, + int maxuuids); +virSecretPtr virSecretLookupByUUIDString(virConnectPtr conn, + const char *uuid); +virSecretPtr virSecretDefineXML (virConnectPtr conn, + const char *xml); +char * virSecretGetUUIDString (virSecretPtr secret); +char * virSecretGetXMLDesc (virSecretPtr secret); +int virSecretSetValue (virSecretPtr secret, + const unsigned char *value, + size_t value_size); +unsigned char * virSecretGetValue (virSecretPtr secret, + size_t *value_size); +int virSecretUndefine (virSecretPtr secret); +int virSecretRef (virSecretPtr secret); +int virSecretFree (virSecretPtr secret); + #ifdef __cplusplus } #endif diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index c06f51e..65080ed 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -292,3 +292,19 @@ LIBVIRT_0.7.0 { } LIBVIRT_0.6.4; # .... define new API here using predicted next version number .... + +LIBVIRT_0.7.1 { + global: + virSecretGetConnect; + virConnectNumOfSecrets; + virConnectListSecrets; + virSecretLookupByUUIDString; + virSecretDefineXML; + virSecretGetUUIDString; + virSecretGetXMLDesc; + virSecretSetValue; + virSecretGetValue; + virSecretUndefine; + virSecretRef; + virSecretFree; +} LIBVIRT_0.7.0; -- 1.6.2.5

On Sun, Aug 16, 2009 at 10:47:54PM +0200, Miloslav Trmač wrote:
This patch adds a "secret" as a separately managed object, using a special-purpose API to transfer the secret values between nodes and libvirt users.
Okay, interesting...
Rather than add explicit accessors for attributes of secrets, and hard-code the "secrets are related to storage volumes" association in the API, the API uses XML to manipulate the association as well as other attributes, similarly to other areas of libvirt.
The user can set attributes of the secret using XML, e.g. <secret ephemeral='no' private='yes'> <uuid>b8eecf55-798e-4db7-b2dd-025b0cf08a36</uuid> <volume>/var/lib/libvirt/images/mail.img</volume> <description>LUKS passphrase for our mail server</description> </secret> If <uuid/> is not specified, it is chosen automatically.
Should secret always be tied to volumes. The API is generic enough that we should make sure we can use this later to get priviledged access to other resources, though right now I don't have a good example in mind.
The secret value can be either generated and stored by libvirt during volume creation, or supplied by the user using virSecretSetValue().
A simple API is provided for enumeration of all secrets. Very large deployments will manage secret IDs automatically, so it is probably not necessary to provide a specialized lookup function (allowing the volume key -> secret ID lookup in less than O(number of secrets)). These functions can eventually be added later.
Changes since the second submission: - Changed API to revolve around a virSecretPtr. The operations are now: virSecretGetConnect virConnectNumOfSecrets virConnectListSecrets virSecretLookupByUUIDString virSecretDefineXML virSecretGetUUIDString virSecretGetXMLDesc virSecretSetValue virSecretGetValue virSecretUndefine virSecretRef virSecretFree
Okay that's completely generic, sounds fine !
- Use an optional <uuid/> element inside <secret/> to pre-specify an UUID in virSecretDefineXML() (default is to choose an UUID automatically) - s/secret_id/uuid/g
Not sure I catch that,
- use "unsigned char *" for secret value
fine, assuming 0 terninated. though this may not work with everything but since we need to import/export to XML, unless uuencoding the value we won't be able to embed something which is not part of XML character range (#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]) unicode code points.
- Use "Secret XML" instead of "Secret attributes XML" in the HTML documentation now that the XML contains the UUID as well. [...] diff --git a/docs/format.html b/docs/format.html
No need to send the generated files in the patch :-) [..]
diff --git a/docs/formatsecret.html.in b/docs/formatsecret.html.in new file mode 100644 index 0000000..7471bf7 --- /dev/null +++ b/docs/formatsecret.html.in @@ -0,0 +1,52 @@ +<html> + <body> + <h1>Secret XML format</h1> + + <ul id="toc"></ul>
it's good to have a document from the start :-) but this lacks a bit of the intended use for the API, i.e. where this may be required to use it.
+ <h2><a name="SecretAttributes">Secret XML</a></h2> + + <p> + Secrets stored by libvirt may have attributes associated with them, using + the <code>secret</code> element. The <code>secret</code> element has two + optional attributes, each with values '<code>yes</code>' and + '<code>no</code>', and defaulting to '<code>no</code>': + </p> + <dl> + <dt><code>ephemeral</code></dt> + <dd>This secret must only be kept in memory, never stored persistently. + </dd> + <dt><code>private</code></dt> + <dd>The value of the secret must not be revealed to any caller of libvirt, + nor to any other node. + </dd> + </dl> + <p> + The top-level <code>secret</code> element may contain the following + elements: + </p> + <dl> + <dt><code>uuid</code></dt> + <dd> + An unique identifier for this secret (not necessarily in the UUID + format). If omitted when defining a new secret, a random UUID is + generated. + </dd> + <dt><code>volume</code></dt> + <dd>Key of a volume this secret is associated with. It is safe to delete + the secret after the volume is deleted. + </dd> + <dt><code>description</code></dt> + <dd>A human-readable description of the purpose of the secret. + </dd> + </dl> + + <h2><a name="example">Example</a></h2> + + <pre> + <secret ephemeral='no' private='yes'> + <volume>/var/lib/libvirt/images/mail.img</volume> + <description>LUKS passphrase for the main hard drive of our mail server</description> + </secret></pre> + </body> +</html> [...] --- /dev/null +++ b/docs/schemas/secret.rng @@ -0,0 +1,44 @@ +<!-- A Relax NG schema for the libvirt secret properties XML format --> +<grammar xmlns="http://relaxng.org/ns/structure/1.0"> + <start> + <ref name='secret'/> + </start> + + <define name='secret'> + <element name='secret'> + <optional> + <attribute name='ephemeral'> + <choice> + <value>yes</value> + <value>no</value> + </choice> + </attribute> + </optional> + <optional> + <attribute name='private'> + <choice> + <value>yes</value> + <value>no</value> + </choice> + </attribute> + </optional> + <interleave> + <optional> + <element name='uuid'> + <text/> + </element> + </optional> + <optional> + <element name='description'> + <text/> + </element> + </optional> + <optional> + <element name='volume'> + <text/> + </element> + </optional> + </interleave> + </element> + </define> +</grammar>
Schemas looks fine,I'm just wondering if at some point we may not have to allow something else than <volume> as the associated target... But ensuing backward compatibility should be no problem if we extend uses.
diff --git a/include/libvirt/libvirt.h b/include/libvirt/libvirt.h index 855f755..fd5a70f 100644 --- a/include/libvirt/libvirt.h +++ b/include/libvirt/libvirt.h @@ -1448,6 +1448,40 @@ void virEventRegisterImpl(virEventAddHandleFunc addHandle, virEventAddTimeoutFunc addTimeout, virEventUpdateTimeoutFunc updateTimeout, virEventRemoveTimeoutFunc removeTimeout); + +/* + * Secret manipulation API + */ + +/** + * virSecret: + * + * A virSecret stores a secret value (e.g. a passphrase or encryption key) + * and associated metadata. + */ +typedef struct _virSecret virSecret; +typedef virSecret *virSecretPtr; + +virConnectPtr virSecretGetConnect (virSecretPtr secret); +int virConnectNumOfSecrets (virConnectPtr conn); +int virConnectListSecrets (virConnectPtr conn, + char **uuids, + int maxuuids); +virSecretPtr virSecretLookupByUUIDString(virConnectPtr conn, + const char *uuid); +virSecretPtr virSecretDefineXML (virConnectPtr conn, + const char *xml);
Let's add an "unsigned int flags" to virSecretDefineXML() especially as we don't know yet the scope of future usages.
+char * virSecretGetUUIDString (virSecretPtr secret); +char * virSecretGetXMLDesc (virSecretPtr secret);
And also add an "unsigned int flags" to virSecretGetXMLDesc
+int virSecretSetValue (virSecretPtr secret, + const unsigned char *value, + size_t value_size); +unsigned char * virSecretGetValue (virSecretPtr secret, + size_t *value_size);
Ah, so we aren't relying on 0 termination, but in that case the value need to be uuencoded in the XML, and that should be made clear in the API description. Actually not having the secret completely in the clear in the XML dump sounds like a good idea.
+int virSecretUndefine (virSecretPtr secret); +int virSecretRef (virSecretPtr secret); +int virSecretFree (virSecretPtr secret); + #ifdef __cplusplus } #endif
Okay, looks fine but I still need to look at the libvirt.c entry point to check comment, and there is a couple of fixes needed. I don't have a good entry point to use for uuecoding/decoding of the secret for XML input/outut. Note that uuecode is really the most common way in XML to pass a random set of bytes, there is even support at some schemas level. We would need to add that check to the rng too (I will look at it), thanks ! Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Wed, Aug 19, 2009 at 11:21:58AM +0200, Daniel Veillard wrote:
On Sun, Aug 16, 2009 at 10:47:54PM +0200, Miloslav Trma?? wrote:
This patch adds a "secret" as a separately managed object, using a special-purpose API to transfer the secret values between nodes and libvirt users.
Okay, interesting...
Rather than add explicit accessors for attributes of secrets, and hard-code the "secrets are related to storage volumes" association in the API, the API uses XML to manipulate the association as well as other attributes, similarly to other areas of libvirt.
The user can set attributes of the secret using XML, e.g. <secret ephemeral='no' private='yes'> <uuid>b8eecf55-798e-4db7-b2dd-025b0cf08a36</uuid> <volume>/var/lib/libvirt/images/mail.img</volume> <description>LUKS passphrase for our mail server</description> </secret> If <uuid/> is not specified, it is chosen automatically.
Should secret always be tied to volumes. The API is generic enough that we should make sure we can use this later to get priviledged access to other resources, though right now I don't have a good example in mind.
[snip]
- use "unsigned char *" for secret value
fine, assuming 0 terninated. though this may not work with everything but since we need to import/export to XML, unless uuencoding the value we won't be able to embed something which is not part of XML character range (#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]) unicode code points.
No need to worry about this, since we're not going to include the secret values in the XML. [snip]
+int virSecretSetValue (virSecretPtr secret, + const unsigned char *value, + size_t value_size); +unsigned char * virSecretGetValue (virSecretPtr secret, + size_t *value_size);
Ah, so we aren't relying on 0 termination, but in that case the value need to be uuencoded in the XML, and that should be made clear in the API description. Actually not having the secret completely in the clear in the XML dump sounds like a good idea.
Yes, the secret value should never be exposed in the XML anyway - that's the primary goal of having this separate API. The secret should only ever be exposed by these GetValue/SetValue APIs, and never logged in any of the libvirt internal code paths. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Wed, Aug 19, 2009 at 10:34:38AM +0100, Daniel P. Berrange wrote:
On Wed, Aug 19, 2009 at 11:21:58AM +0200, Daniel Veillard wrote:
On Sun, Aug 16, 2009 at 10:47:54PM +0200, Miloslav Trma?? wrote:
This patch adds a "secret" as a separately managed object, using a special-purpose API to transfer the secret values between nodes and libvirt users.
Okay, interesting...
Rather than add explicit accessors for attributes of secrets, and hard-code the "secrets are related to storage volumes" association in the API, the API uses XML to manipulate the association as well as other attributes, similarly to other areas of libvirt.
The user can set attributes of the secret using XML, e.g. <secret ephemeral='no' private='yes'> <uuid>b8eecf55-798e-4db7-b2dd-025b0cf08a36</uuid> <volume>/var/lib/libvirt/images/mail.img</volume> <description>LUKS passphrase for our mail server</description> </secret> If <uuid/> is not specified, it is chosen automatically.
Should secret always be tied to volumes. The API is generic enough that we should make sure we can use this later to get priviledged access to other resources, though right now I don't have a good example in mind.
[snip]
- use "unsigned char *" for secret value
fine, assuming 0 terninated. though this may not work with everything but since we need to import/export to XML, unless uuencoding the value we won't be able to embed something which is not part of XML character range (#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]) unicode code points.
No need to worry about this, since we're not going to include the secret values in the XML.
Whoops, right it's not supposed to show up there. Okay this is a non-issue :-)
Yes, the secret value should never be exposed in the XML anyway - that's the primary goal of having this separate API. The secret should only ever be exposed by these GetValue/SetValue APIs, and never logged in any of the libvirt internal code paths.
Yes makes sense, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Sun, Aug 16, 2009 at 10:47:54PM +0200, Miloslav Trma?? wrote:
This patch adds a "secret" as a separately managed object, using a special-purpose API to transfer the secret values between nodes and libvirt users.
Rather than add explicit accessors for attributes of secrets, and hard-code the "secrets are related to storage volumes" association in the API, the API uses XML to manipulate the association as well as other attributes, similarly to other areas of libvirt.
The user can set attributes of the secret using XML, e.g. <secret ephemeral='no' private='yes'> <uuid>b8eecf55-798e-4db7-b2dd-025b0cf08a36</uuid> <volume>/var/lib/libvirt/images/mail.img</volume> <description>LUKS passphrase for our mail server</description> </secret> If <uuid/> is not specified, it is chosen automatically.
The secret value can be either generated and stored by libvirt during volume creation, or supplied by the user using virSecretSetValue().
A simple API is provided for enumeration of all secrets. Very large deployments will manage secret IDs automatically, so it is probably not necessary to provide a specialized lookup function (allowing the volume key -> secret ID lookup in less than O(number of secrets)). These functions can eventually be added later.
If the guest XML contains the UUID of the secret, we already have O(1) lookup based on UUID. Adding a lookup based on volume could be convenient later, but not critical.
Changes since the second submission: - Changed API to revolve around a virSecretPtr. The operations are now: virSecretGetConnect virConnectNumOfSecrets virConnectListSecrets virSecretLookupByUUIDString virSecretDefineXML virSecretGetUUIDString virSecretGetXMLDesc virSecretSetValue virSecretGetValue virSecretUndefine virSecretRef virSecretFree
So just to enumerate some of the scenarios we're trying to address: - Auto-created secrets for qcow2 using local DB 1. App calls virStorageVolCreateXML() to create the qcow2 volume requesting encryption with auto-created secret 2. Libvirt generates a random passphrase, and internally creates a secret and sets its value to the passphrase, and stores it in the local DB 3. App defines guest config with virDomainDefineXML() 4. App boots the guest with virDomainCreate() 5. libvirt automatically fetches key out of its local DB - Auto-created secrets for qcow2 with no local DB storage 1. App calls virStorageVolCreateXML() to create the qcow2 volume requesting encryption with auto-created secret 2. Libvirt generates a random passphrase, and internally creates a secret and sets its value to the passphrase, and stores it in the local DB 3. App defines guest config with virDomainDefineXML() 4. App boots the guest with virDomainCreate() 5. libvirt automatically fetches key out of memory 6. App fetches auto-generated passphrase with virSecretGetValue and saves it somewhere safe - Manually specified passphrases with no local DB storage 1. App calls virSecretDefineXML to create a secret, ephemeral set 2. App calls virSecretSetValue() to set the passphrase 3. App calls virStorageVolCreateXML() to create the qcow2 volume requesting encryption 4. App defines guest config with virDomainDefineXML() 5. App boots the guest with virDomainCreate() 6. libvirt automatically fetches key from memory - External off-node keystore with cluster of hosts, starting a guest 1. App calls virSecretDefineXML to create a secret for the VM to be deployed 2. App calls virSecretSetValue() to set passphrase 3. App calls virDomainCreateXML to create a transient guest 4. App calls virSecretUndefine to remove the secret - External off-node keystore with cluster of hosts, creating a volume 1. App calls virSecretDefineXML to create a secret for the VM to be deployed 2. App calls virSecretSetValue() to set passphrase 3. App calls virStorageVolCreateXML to create a volume 4. App calls virSecretUndefine to remove the secret I could go on with other various scenarios, bt I think the API we have allows for all the cases we care about, both external 3rd party keystore and a local libvirt managed one. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

Adds a new driver type. Changes since the second submission: - Update for changed public API - Add virSecretPtr handling - s/secret_id/uuid/g - use "unsigned char *" for secret value --- include/libvirt/virterror.h | 1 + src/datatypes.c | 153 +++++++++++++++++++++++++++++++++++++++++++ src/datatypes.h | 28 ++++++++ src/driver.h | 57 ++++++++++++++++ src/libvirt.c | 55 +++++++++++++++ src/libvirt_private.syms | 2 + src/virterror.c | 6 ++ 7 files changed, 302 insertions(+), 0 deletions(-) diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index e4d013f..5cbb120 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -166,6 +166,7 @@ typedef enum { VIR_ERR_NO_INTERFACE, /* interface driver not running */ VIR_ERR_INVALID_INTERFACE, /* invalid interface object */ VIR_ERR_MULTIPLE_INTERFACES, /* more than one matching interface found */ + VIR_WAR_NO_SECRET, /* failed to start secret storage */ } virErrorNumber; /** diff --git a/src/datatypes.c b/src/datatypes.c index 8b3f8c3..5db3899 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -109,6 +109,23 @@ virStorageVolFreeName(virStorageVolPtr vol, const char *name ATTRIBUTE_UNUSED) } /** + * virSecretFreeName: + * @secret_: a secret object + * + * Destroy the vol object, this is just used by the vol hash callback. + * + * Returns 0 in case of success and -1 in case of failure. + */ +static void +virSecretFreeName(void *secret_, const char *name ATTRIBUTE_UNUSED) +{ + virSecretPtr secret; + + secret = secret_; + virUnrefSecret(secret); +} + +/** * virGetConnect: * * Allocates a new hypervisor connection structure @@ -152,6 +169,9 @@ virGetConnect(void) { ret->nodeDevices = virHashCreate(256); if (ret->nodeDevices == NULL) goto failed; + ret->secrets = virHashCreate(20); + if (ret->secrets == NULL) + goto failed; ret->refs = 1; return(ret); @@ -170,6 +190,8 @@ failed: virHashFree(ret->storageVols, (virHashDeallocator) virStorageVolFreeName); if (ret->nodeDevices != NULL) virHashFree(ret->nodeDevices, (virHashDeallocator) virNodeDeviceFree); + if (ret->secrets != NULL) + virHashFree(ret->secrets, virSecretFreeName); virMutexDestroy(&ret->lock); VIR_FREE(ret); @@ -201,6 +223,8 @@ virReleaseConnect(virConnectPtr conn) { virHashFree(conn->storageVols, (virHashDeallocator) virStorageVolFreeName); if (conn->nodeDevices != NULL) virHashFree(conn->nodeDevices, (virHashDeallocator) virNodeDeviceFree); + if (conn->secrets != NULL) + virHashFree(conn->secrets, virSecretFreeName); virResetError(&conn->err); @@ -1109,3 +1133,132 @@ virUnrefNodeDevice(virNodeDevicePtr dev) { virMutexUnlock(&dev->conn->lock); return (refs); } + +/** + * virGetSecret: + * @conn: the hypervisor connection + * @uuid: secret UUID + * + * Lookup if the secret is already registered for that connection, if so return + * a pointer to it, otherwise allocate a new structure, and register it in the + * table. In any case a corresponding call to virFreeSecret() is needed to not + * leak data. + * + * Returns a pointer to the secret, or NULL in case of failure + */ +virSecretPtr +virGetSecret(virConnectPtr conn, const char *uuid) +{ + virSecretPtr ret = NULL; + + if (!VIR_IS_CONNECT(conn) || uuid == NULL) { + virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); + return NULL; + } + virMutexLock(&conn->lock); + + ret = virHashLookup(conn->secrets, uuid); + if (ret == NULL) { + if (VIR_ALLOC(ret) < 0) { + virMutexUnlock(&conn->lock); + virReportOOMError(conn); + goto error; + } + ret->magic = VIR_SECRET_MAGIC; + ret->conn = conn; + ret->uuid = strdup(uuid); + if (ret->uuid == NULL) { + virMutexUnlock(&conn->lock); + virReportOOMError(conn); + goto error; + } + + if (virHashAddEntry(conn->secrets, uuid, ret) < 0) { + virMutexUnlock(&conn->lock); + virLibConnError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("failed to add secret to conn hash table")); + goto error; + } + conn->refs++; + } + ret->refs++; + virMutexUnlock(&conn->lock); + return ret; + +error: + if (ret != NULL) { + VIR_FREE(ret->uuid); + VIR_FREE(ret); + } + return NULL; +} + +/** + * virReleaseSecret: + * @secret: the secret to release + * + * Unconditionally release all memory associated with a secret. The conn.lock + * mutex must be held prior to calling this, and will be released prior to this + * returning. The secret obj must not be used once this method returns. + * + * It will also unreference the associated connection object, which may also be + * released if its ref count hits zero. + */ +static void +virReleaseSecret(virSecretPtr secret) { + virConnectPtr conn = secret->conn; + DEBUG("release secret %p %s", secret, secret->uuid); + + if (virHashRemoveEntry(conn->secrets, secret->uuid, NULL) < 0) { + virMutexUnlock(&conn->lock); + virLibConnError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("secret missing from connection hash table")); + conn = NULL; + } + + secret->magic = -1; + VIR_FREE(secret->uuid); + VIR_FREE(secret); + + if (conn) { + DEBUG("unref connection %p %d", conn, conn->refs); + conn->refs--; + if (conn->refs == 0) { + virReleaseConnect(conn); + /* Already unlocked mutex */ + return; + } + virMutexUnlock(&conn->lock); + } +} + +/** + * virUnrefSecret: + * @secret: the secret to unreference + * + * Unreference the secret. If the use count drops to zero, the structure is + * actually freed. + * + * Returns the reference count or -1 in case of failure. + */ +int +virUnrefSecret(virSecretPtr secret) { + int refs; + + if (!VIR_IS_CONNECTED_SECRET(secret)) { + virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); + return -1; + } + virMutexLock(&secret->conn->lock); + DEBUG("unref secret %p %s %d", secret, secret->uuid, secret->refs); + secret->refs--; + refs = secret->refs; + if (refs == 0) { + virReleaseSecret(secret); + /* Already unlocked mutex */ + return 0; + } + + virMutexUnlock(&secret->conn->lock); + return refs; +} diff --git a/src/datatypes.h b/src/datatypes.h index da83e02..56c3777 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -98,6 +98,16 @@ #define VIR_IS_NODE_DEVICE(obj) ((obj) && (obj)->magic==VIR_NODE_DEVICE_MAGIC) #define VIR_IS_CONNECTED_NODE_DEVICE(obj) (VIR_IS_NODE_DEVICE(obj) && VIR_IS_CONNECT((obj)->conn)) +/** + * VIR_SECRET_MAGIC: + * + * magic value used to protect the API when pointers to secret structures are + * passed down by the users. + */ +#define VIR_SECRET_MAGIC 0x5678DEAD +#define VIR_IS_SECRET(obj) ((obj) && (obj)->magic==VIR_SECRET_MAGIC) +#define VIR_IS_CONNECTED_SECRET(obj) (VIR_IS_SECRET(obj) && VIR_IS_CONNECT((obj)->conn)) + /** * _virConnect: @@ -119,6 +129,7 @@ struct _virConnect { virInterfaceDriverPtr interfaceDriver; virStorageDriverPtr storageDriver; virDeviceMonitorPtr deviceMonitor; + virSecretDriverPtr secretDriver; /* Private data pointer which can be used by driver and * network driver as they wish. @@ -149,6 +160,7 @@ struct _virConnect { virHashTablePtr storagePools;/* hash table for known storage pools */ virHashTablePtr storageVols;/* hash table for known storage vols */ virHashTablePtr nodeDevices; /* hash table for known node devices */ + virHashTablePtr secrets; /* hash taboe for known secrets */ int refs; /* reference count */ }; @@ -233,6 +245,18 @@ struct _virNodeDevice { char *parent; /* parent device name */ }; +/** + * _virSecret: + * + * Internal structure associated with a secret + */ +struct _virSecret { + unsigned int magic; /* specific value to check */ + int refs; /* reference count */ + virConnectPtr conn; /* pointer back to the connection */ + char *uuid; /* ID of the secret */ +}; + /************************************************************************ * * @@ -270,4 +294,8 @@ virNodeDevicePtr virGetNodeDevice(virConnectPtr conn, const char *name); int virUnrefNodeDevice(virNodeDevicePtr dev); +virSecretPtr virGetSecret(virConnectPtr conn, + const char *uuid); +int virUnrefSecret(virSecretPtr secret); + #endif diff --git a/src/driver.h b/src/driver.h index 79d46ff..9ed76bf 100644 --- a/src/driver.h +++ b/src/driver.h @@ -6,6 +6,9 @@ #ifndef __VIR_DRIVER_H__ #define __VIR_DRIVER_H__ +#include "config.h" +#include <stdbool.h> + #include <libxml/uri.h> #include "internal.h" @@ -799,6 +802,59 @@ struct _virDeviceMonitor { virDrvNodeDeviceDestroy deviceDestroy; }; +typedef virSecretPtr + (*virDrvSecretLookupByUUIDString) (virConnectPtr conn, + const char *uuid); +typedef virSecretPtr + (*virDrvSecretDefineXML) (virConnectPtr conn, + const char *xml); +typedef char * + (*virDrvSecretGetXMLDesc) (virSecretPtr secret); +typedef int + (*virDrvSecretSetValue) (virSecretPtr secret, + const unsigned char *value, + size_t value_size); +typedef unsigned char * + (*virDrvSecretGetValue) (virSecretPtr secret, + size_t *value_size, + bool libvirt_internal_call); +typedef int + (*virDrvSecretUndefine) (virSecretPtr secret); +typedef int + (*virDrvSecretNumOfSecrets) (virConnectPtr conn); +typedef int + (*virDrvSecretListSecrets) (virConnectPtr conn, + char **uuids, + int maxuuids); + +typedef struct _virSecretDriver virSecretDriver; +typedef virSecretDriver *virSecretDriverPtr; + +/** + * _virSecretDriver: + * + * Structure associated to a driver for storing secrets, defining the various + * entry points for it. + * + * All drivers must support the following fields/methods: + * - open + * - close + */ +struct _virSecretDriver { + const char *name; + virDrvOpen open; + virDrvClose close; + + virDrvSecretNumOfSecrets numOfSecrets; + virDrvSecretListSecrets listSecrets; + virDrvSecretLookupByUUIDString lookupByUUIDString; + virDrvSecretDefineXML defineXML; + virDrvSecretGetXMLDesc getXMLDesc; + virDrvSecretSetValue setValue; + virDrvSecretGetValue getValue; + virDrvSecretUndefine undefine; +}; + /* * Registration * TODO: also need ways to (des)activate a given driver @@ -809,6 +865,7 @@ int virRegisterNetworkDriver(virNetworkDriverPtr); int virRegisterInterfaceDriver(virInterfaceDriverPtr); int virRegisterStorageDriver(virStorageDriverPtr); int virRegisterDeviceMonitor(virDeviceMonitorPtr); +int virRegisterSecretDriver(virSecretDriverPtr); #ifdef WITH_LIBVIRTD int virRegisterStateDriver(virStateDriverPtr); #endif diff --git a/src/libvirt.c b/src/libvirt.c index e450ad9..d6a023f 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -86,6 +86,8 @@ static virStorageDriverPtr virStorageDriverTab[MAX_DRIVERS]; static int virStorageDriverTabCount = 0; static virDeviceMonitorPtr virDeviceMonitorTab[MAX_DRIVERS]; static int virDeviceMonitorTabCount = 0; +static virSecretDriverPtr virSecretDriverTab[MAX_DRIVERS]; +static int virSecretDriverTabCount = 0; #ifdef WITH_LIBVIRTD static virStateDriverPtr virStateDriverTab[MAX_DRIVERS]; static int virStateDriverTabCount = 0; @@ -684,6 +686,37 @@ virRegisterDeviceMonitor(virDeviceMonitorPtr driver) } /** + * virRegisterSecretDriver: + * @driver: pointer to a secret driver block + * + * Register a secret driver + * + * Returns the driver priority or -1 in case of error. + */ +int +virRegisterSecretDriver(virSecretDriverPtr driver) +{ + if (virInitialize() < 0) + return -1; + + if (driver == NULL) { + virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(-1); + } + + if (virSecretDriverTabCount >= MAX_DRIVERS) { + virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(-1); + } + + DEBUG ("registering %s as secret driver %d", + driver->name, virSecretDriverTabCount); + + virSecretDriverTab[virSecretDriverTabCount] = driver; + return virSecretDriverTabCount++; +} + +/** * virRegisterDriver: * @driver: pointer to a driver block * @@ -1096,6 +1129,26 @@ do_open (const char *name, } } + /* Secret manipulation driver. Optional */ + for (i = 0; i < virSecretDriverTabCount; i++) { + res = virSecretDriverTab[i]->open (ret, auth, flags); + DEBUG("secret driver %d %s returned %s", + i, virSecretDriverTab[i]->name, + res == VIR_DRV_OPEN_SUCCESS ? "SUCCESS" : + (res == VIR_DRV_OPEN_DECLINED ? "DECLINED" : + (res == VIR_DRV_OPEN_ERROR ? "ERROR" : "unknown status"))); + if (res == VIR_DRV_OPEN_ERROR) { + if (STREQ(virSecretDriverTab[i]->name, "remote")) { + virLibConnWarning (NULL, VIR_WAR_NO_SECRET, + "Is the daemon running ?"); + } + break; + } else if (res == VIR_DRV_OPEN_SUCCESS) { + ret->secretDriver = virSecretDriverTab[i]; + break; + } + } + return ret; failed: @@ -1229,6 +1282,8 @@ virConnectClose(virConnectPtr conn) conn->storageDriver->close (conn); if (conn->deviceMonitor) conn->deviceMonitor->close (conn); + if (conn->secretDriver) + conn->secretDriver->close (conn); conn->driver->close (conn); if (virUnrefConnect(conn) < 0) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 23fa01b..61f18e6 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -52,10 +52,12 @@ virGetInterface; virGetNetwork; virGetStoragePool; virGetStorageVol; +virGetSecret; virUnrefStorageVol; virGetNodeDevice; virUnrefDomain; virUnrefConnect; +virUnrefSecret; # domain_conf.h diff --git a/src/virterror.c b/src/virterror.c index 362d8ef..83a0830 100644 --- a/src/virterror.c +++ b/src/virterror.c @@ -1068,6 +1068,12 @@ virErrorMsg(virErrorNumber error, const char *info) else errmsg = _("multiple matching interfaces found: %s"); break; + case VIR_WAR_NO_SECRET: + if (info == NULL) + errmsg = _("Failed to find a secret storage driver"); + else + errmsg = _("Failed to find a secret storage driver: %s"); + break; } return (errmsg); } -- 1.6.2.5

On Sun, Aug 16, 2009 at 10:47:55PM +0200, Miloslav Trmač wrote:
Adds a new driver type. [...] +++ b/src/datatypes.c @@ -109,6 +109,23 @@ virStorageVolFreeName(virStorageVolPtr vol, const char *name ATTRIBUTE_UNUSED) }
/** + * virSecretFreeName: + * @secret_: a secret object + * + * Destroy the vol object, this is just used by the vol hash callback.
+ * Returns 0 in case of success and -1 in case of failure.
Hum, comment probably need to be updated, isn't it ?
+ */ +static void +virSecretFreeName(void *secret_, const char *name ATTRIBUTE_UNUSED) +{ + virSecretPtr secret; + + secret = secret_; + virUnrefSecret(secret); +} + +/** * virGetConnect: * * Allocates a new hypervisor connection structure
datatype.c part looks fine
diff --git a/src/datatypes.h b/src/datatypes.h index da83e02..56c3777 100644 --- a/src/datatypes.h +++ b/src/datatypes.h [...]
+typedef virSecretPtr + (*virDrvSecretLookupByUUIDString) (virConnectPtr conn, + const char *uuid); +typedef virSecretPtr + (*virDrvSecretDefineXML) (virConnectPtr conn,
the flags should be propagated in the internal drivers APIs
+typedef char * + (*virDrvSecretGetXMLDesc) (virSecretPtr secret); +typedef int + (*virDrvSecretSetValue) (virSecretPtr secret, + const unsigned char *value, here too
+typedef unsigned char * + (*virDrvSecretGetValue) (virSecretPtr secret, + size_t *value_size, + bool libvirt_internal_call); +typedef int + (*virDrvSecretUndefine) (virSecretPtr secret); +typedef int + (*virDrvSecretNumOfSecrets) (virConnectPtr conn); +typedef int + (*virDrvSecretListSecrets) (virConnectPtr conn, + char **uuids, + int maxuuids); and here
looks fine overall, ACK once the flags gets added, thanks ! Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

----- "Daniel Veillard" <veillard@redhat.com> wrote:
On Sun, Aug 16, 2009 at 10:47:55PM +0200, Miloslav Trmač wrote:
/** + * virSecretFreeName: + * @secret_: a secret object + * + * Destroy the vol object, this is just used by the vol hash callback. + * Returns 0 in case of success and -1 in case of failure.
Hum, comment probably need to be updated, isn't it ? Of course :)
Thanks for the review, Mirek

Changes since the second submission: - Update for the changed public API - s/secret_id/uuid/g - use "unsigned char *" for secret value --- include/libvirt/virterror.h | 2 + src/libvirt.c | 499 +++++++++++++++++++++++++++++++++++++++++++ src/virterror.c | 9 + 3 files changed, 510 insertions(+), 0 deletions(-) diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index 5cbb120..62cad88 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -67,6 +67,7 @@ typedef enum { VIR_FROM_ONE, /* Error from OpenNebula driver */ VIR_FROM_ESX, /* Error from ESX driver */ VIR_FROM_PHYP, /* Error from IBM power hypervisor */ + VIR_FROM_SECRET, /* Error from secret storage */ } virErrorDomain; @@ -167,6 +168,7 @@ typedef enum { VIR_ERR_INVALID_INTERFACE, /* invalid interface object */ VIR_ERR_MULTIPLE_INTERFACES, /* more than one matching interface found */ VIR_WAR_NO_SECRET, /* failed to start secret storage */ + VIR_ERR_INVALID_SECRET, /* invalid secret */ } virErrorNumber; /** diff --git a/src/libvirt.c b/src/libvirt.c index d6a023f..6b584b2 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -562,6 +562,31 @@ virLibNodeDeviceError(virNodeDevicePtr dev, virErrorNumber error, } /** + * virLibSecretError: + * @secret: the secret if available + * @error: the error number + * @info: extra information string + * + * Handle an error at the secret level + */ +static void +virLibSecretError(virSecretPtr secret, virErrorNumber error, const char *info) +{ + virConnectPtr conn = NULL; + const char *errmsg; + + if (error == VIR_ERR_OK) + return; + + errmsg = virErrorMsg(error, info); + if (error != VIR_ERR_INVALID_SECRET) + conn = secret->conn; + + virRaiseError(conn, NULL, NULL, VIR_FROM_SECRET, error, VIR_ERR_ERROR, + errmsg, info, NULL, 0, 0, errmsg, info); +} + +/** * virRegisterNetworkDriver: * @driver: pointer to a network driver block * @@ -8695,3 +8720,477 @@ error: virSetConnError(conn); return -1; } + +/** + * virSecretGetConnect: + * @secret: A virSecret secret + * + * Provides the connection pointer associated with a secret. The reference + * counter on the connection is not increased by this call. + * + * WARNING: When writing libvirt bindings in other languages, do not use this + * function. Instead, store the connection and the secret object together. + * + * Returns the virConnectPtr or NULL in case of failure. + */ +virConnectPtr +virSecretGetConnect (virSecretPtr secret) +{ + DEBUG("secret=%p", secret); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_SECRET (secret)) { + virLibSecretError (NULL, VIR_ERR_INVALID_SECRET, __FUNCTION__); + return NULL; + } + return secret->conn; +} + +/** + * virConnectNumOfSecrets: + * @conn: virConnect connection + * + * Fetch number of currently defined secrets. + * + * Returns the number currently defined secrets. + */ +int +virConnectNumOfSecrets(virConnectPtr conn) +{ + VIR_DEBUG("conn=%p", conn); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return -1; + } + + if (conn->secretDriver != NULL && + conn->secretDriver->numOfSecrets != NULL) { + int ret; + + ret = conn->secretDriver->numOfSecrets(conn); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + /* Copy to connection error object for back compatability */ + virSetConnError(conn); + return -1; +} + +/** + * virConnectListSecrets: + * @conn: virConnect connection + * @uuids: Pointer to an array to store the UUIDs + * @maxuuids: size of the array. + * + * List UUIDs of defined secrets, store pointers to names in uuids. + * + * Returns the number of UUIDs provided in the array, or -1 on failure. + */ +int +virConnectListSecrets(virConnectPtr conn, char **uuids, int maxuuids) +{ + VIR_DEBUG("conn=%p, uuids=%p, maxuuids=%d", conn, uuids, maxuuids); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return -1; + } + if (uuids == NULL || maxuuids < 0) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + goto error; + } + + if (conn->secretDriver != NULL && conn->secretDriver->listSecrets != NULL) { + int ret; + + ret = conn->secretDriver->listSecrets(conn, uuids, maxuuids); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + /* Copy to connection error object for back compatability */ + virSetConnError(conn); + return -1; +} + +/** + * virSecretLookupByUUIDString: + * @conn: virConnect connection + * @uuid: ID of a secret + * + * Fetches a secret based on uuid. + * + * Returns the secret on success, or NULL on failure. + */ +virSecretPtr +virSecretLookupByUUIDString(virConnectPtr conn, const char *uuid) +{ + VIR_DEBUG("conn=%p, uuid=%s", conn, uuid); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return NULL; + } + if (uuid == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + goto error; + } + + if (conn->secretDriver != NULL && + conn->secretDriver->lookupByUUIDString != NULL) { + virSecretPtr ret; + + ret = conn->secretDriver->lookupByUUIDString(conn, uuid); + if (ret == NULL) + goto error; + return ret; + } + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + /* Copy to connection error object for back compatability */ + virSetConnError(conn); + return NULL; +} + +/** + * virSecretDefineXML: + * @conn: virConnect connection + * @xml: XML describing the secret. + * + * If XML specifies an UUID, locates the specified secret and replaces all + * attributes of the secret specified by UUID by attributes specified in xml + * (any attributes not specified in xml are discarded). + * + * Otherwise, creates a new secret with an automatically chosen UUID, and + * initializes its attributes from xml. + * + * Returns a the secret on success, NULL on failure. + */ +virSecretPtr +virSecretDefineXML(virConnectPtr conn, const char *xml) +{ + VIR_DEBUG("conn=%p, xml=%s", conn, xml); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return NULL; + } + if (conn->flags & VIR_CONNECT_RO) { + virLibConnError(conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + if (xml == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + goto error; + } + + if (conn->secretDriver != NULL && conn->secretDriver->defineXML != NULL) { + virSecretPtr ret; + + ret = conn->secretDriver->defineXML(conn, xml); + if (ret == NULL) + goto error; + return ret; + } + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + /* Copy to connection error object for back compatability */ + virSetConnError(conn); + return NULL; +} + +/** + * virSecretGetUUIDString: + * @secret: A virSecret secret + * + * Fetches the UUID of the secret. + * + * Returns ID of the secret (not necessarily in the UUID format) on success, + * NULL on failure. The caller must free() the ID. + */ +char * +virSecretGetUUIDString(virSecretPtr secret) +{ + char *ret; + + VIR_DEBUG("secret=%p", secret); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_SECRET(secret)) { + virLibSecretError(NULL, VIR_ERR_INVALID_SECRET, __FUNCTION__); + return NULL; + } + + ret = strdup(secret->uuid); + if (ret != NULL) + return ret; + + virReportOOMError(secret->conn); + virSetConnError(secret->conn); + return NULL; +} + +/** + * virSecretGetXMLDesc: + * @secret: A virSecret secret + * + * Fetches an XML document describing attributes of the secret. + * + * Returns the XML document on success, NULL on failure. The caller must + * free() the XML. + */ +char * +virSecretGetXMLDesc(virSecretPtr secret) +{ + virConnectPtr conn; + + VIR_DEBUG("secret=%p", secret); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_SECRET(secret)) { + virLibSecretError(NULL, VIR_ERR_INVALID_SECRET, __FUNCTION__); + return NULL; + } + + conn = secret->conn; + if (conn->secretDriver != NULL && conn->secretDriver->getXMLDesc != NULL) { + char *ret; + + ret = conn->secretDriver->getXMLDesc(secret); + if (ret == NULL) + goto error; + return ret; + } + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + /* Copy to connection error object for back compatability */ + virSetConnError(conn); + return NULL; +} + +/** + * virSecretSetValue: + * @secret: A virSecret secret + * @value: Value of the secret + * @value_size: Size of the value + * + * Sets the value of a secret. + * + * Returns 0 on success, -1 on failure. + */ +int +virSecretSetValue(virSecretPtr secret, const unsigned char *value, + size_t value_size) +{ + virConnectPtr conn; + + VIR_DEBUG("secret=%p, value=%p, value_size=%zu", secret, value, value_size); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_SECRET(secret)) { + virLibSecretError(NULL, VIR_ERR_INVALID_SECRET, __FUNCTION__); + return -1; + } + conn = secret->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibSecretError(secret, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + if (value == NULL) { + virLibSecretError(secret, VIR_ERR_INVALID_ARG, __FUNCTION__); + goto error; + } + + if (conn->secretDriver != NULL && conn->secretDriver->setValue != NULL) { + int ret; + + ret = conn->secretDriver->setValue(secret, value, value_size); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + /* Copy to connection error object for back compatability */ + virSetConnError(conn); + return -1; +} + +/** + * virSecretGetValue: + * @secret: A virSecret connection + * @value_size: Place for storing size of the secret value + * + * Fetches the value of a secret. + * + * Returns the secret value on success, NULL on failure. The caller must + * free() the secret value. + */ +unsigned char * +virSecretGetValue(virSecretPtr secret, size_t *value_size) +{ + virConnectPtr conn; + + VIR_DEBUG("secret=%p, value_size=%p", secret, value_size); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_SECRET(secret)) { + virLibSecretError(NULL, VIR_ERR_INVALID_SECRET, __FUNCTION__); + return NULL; + } + conn = secret->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibSecretError(secret, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + if (value_size == NULL) { + virLibSecretError(secret, VIR_ERR_INVALID_ARG, __FUNCTION__); + goto error; + } + + if (conn->secretDriver != NULL && conn->secretDriver->getValue != NULL) { + unsigned char *ret; + + ret = conn->secretDriver->getValue(secret, value_size, false); + if (ret == NULL) + goto error; + return ret; + } + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + /* Copy to connection error object for back compatability */ + virSetConnError(conn); + return NULL; +} + +/** + * virSecretUndefine: + * @secret: A virSecret secret + * + * Deletes the specified secret. This does not free the associated + * virSecretPtr object. + * + * Returns 0 on success, -1 on failure. + */ +int +virSecretUndefine(virSecretPtr secret) +{ + virConnectPtr conn; + + VIR_DEBUG("secret=%p", secret); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_SECRET(secret)) { + virLibSecretError(NULL, VIR_ERR_INVALID_SECRET, __FUNCTION__); + return -1; + } + conn = secret->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibSecretError(secret, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + if (conn->secretDriver != NULL && conn->secretDriver->undefine != NULL) { + int ret; + + ret = conn->secretDriver->undefine(secret); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + /* Copy to connection error object for back compatability */ + virSetConnError(conn); + return -1; +} + +/** + * virSecretRef: + * @secret: the secret to hold a reference on + * + * Increment the reference count on the secret. For each additional call to + * this method, there shall be a corresponding call to virSecretFree to release + * the reference count, once the caller no longer needs the reference to this + * object. + * + * This method is typically useful for applications where multiple threads are + * using a connection, and it is required that the connection remain open until + * all threads have finished using it. ie, each new thread using a secret would + * increment the reference count. + * + * Returns 0 in case of success, -1 in case of failure. + */ +int +virSecretRef(virSecretPtr secret) +{ + if (!VIR_IS_CONNECTED_SECRET(secret)) { + virLibSecretError(NULL, VIR_ERR_INVALID_SECRET, __FUNCTION__); + return -1; + } + virMutexLock(&secret->conn->lock); + DEBUG("secret=%p refs=%d", secret, secret->refs); + secret->refs++; + virMutexUnlock(&secret->conn->lock); + return 0; +} + +/** + * virSecretFree: + * @secret: pointer to a secret + * + * Release the secret handle. The underlying secret continues to exist. + * + * Return 0 on success, or -1 on error + */ +int +virSecretFree(virSecretPtr secret) +{ + DEBUG("secret=%p", secret); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_SECRET(secret)) { + virLibSecretError(NULL, VIR_ERR_INVALID_SECRET, __FUNCTION__); + return -1; + } + if (virUnrefSecret(secret) < 0) + return -1; + return 0; +} diff --git a/src/virterror.c b/src/virterror.c index 83a0830..2a3cdaf 100644 --- a/src/virterror.c +++ b/src/virterror.c @@ -169,6 +169,9 @@ static const char *virErrorDomainName(virErrorDomain domain) { case VIR_FROM_ESX: dom = "ESX "; break; + case VIR_FROM_SECRET: + dom = "Secret Storage "; + break; } return(dom); } @@ -1074,6 +1077,12 @@ virErrorMsg(virErrorNumber error, const char *info) else errmsg = _("Failed to find a secret storage driver: %s"); break; + case VIR_ERR_INVALID_SECRET: + if (info == NULL) + errmsg = _("Invalid secret"); + else + errmsg = _("Invalid secret: %s"); + break; } return (errmsg); } -- 1.6.2.5

On Sun, Aug 16, 2009 at 10:47:56PM +0200, Miloslav Trmač wrote:
Changes since the second submission: - Update for the changed public API - s/secret_id/uuid/g - use "unsigned char *" for secret value [...] +/** + * virConnectListSecrets: + * @conn: virConnect connection + * @uuids: Pointer to an array to store the UUIDs + * @maxuuids: size of the array.
just add flags
+ * + * List UUIDs of defined secrets, store pointers to names in uuids. + * + * Returns the number of UUIDs provided in the array, or -1 on failure. + */ +int +virConnectListSecrets(virConnectPtr conn, char **uuids, int maxuuids) +{ +/** + * virSecretDefineXML: + * @conn: virConnect connection + * @xml: XML describing the secret.
let's add flags here too
+ * If XML specifies an UUID, locates the specified secret and replaces all + * attributes of the secret specified by UUID by attributes specified in xml + * (any attributes not specified in xml are discarded). + * + * Otherwise, creates a new secret with an automatically chosen UUID, and + * initializes its attributes from xml. + * + * Returns a the secret on success, NULL on failure. + */ [...] +/** + * virSecretGetXMLDesc: + * @secret: A virSecret secret here too + * Fetches an XML document describing attributes of the secret. + * + * Returns the XML document on success, NULL on failure. The caller must + * free() the XML. + */ +char * +virSecretGetXMLDesc(virSecretPtr secret)
+/** + * virSecretSetValue: + * @secret: A virSecret secret + * @value: Value of the secret + * @value_size: Size of the value
here
+ * Sets the value of a secret. + * + * Returns 0 on success, -1 on failure. + */
+/** + * virSecretGetValue: + * @secret: A virSecret connection + * @value_size: Place for storing size of the secret value
and here
+ * Fetches the value of a secret. + * + * Returns the secret value on success, NULL on failure. The caller must + * free() the secret value. + */
otherwise libvirt.c code looks just fine
diff --git a/src/virterror.c b/src/virterror.c index 83a0830..2a3cdaf 100644 --- a/src/virterror.c +++ b/src/virterror.c
ACK once flags are added, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Changes since the second submission: - Update for the changed public API - s/secret_id/uuid/g --- qemud/remote_dispatch_args.h | 7 ++ qemud/remote_dispatch_prototypes.h | 56 +++++++++++++++ qemud/remote_dispatch_ret.h | 6 ++ qemud/remote_dispatch_table.h | 40 +++++++++++ qemud/remote_protocol.c | 132 ++++++++++++++++++++++++++++++++++++ qemud/remote_protocol.h | 118 ++++++++++++++++++++++++++++++++ qemud/remote_protocol.x | 79 +++++++++++++++++++++- 7 files changed, 437 insertions(+), 1 deletions(-) diff --git a/qemud/remote_dispatch_args.h b/qemud/remote_dispatch_args.h index 9dacfb8..dcf7ddf 100644 --- a/qemud/remote_dispatch_args.h +++ b/qemud/remote_dispatch_args.h @@ -117,3 +117,10 @@ remote_domain_xml_from_native_args val_remote_domain_xml_from_native_args; remote_domain_xml_to_native_args val_remote_domain_xml_to_native_args; remote_list_defined_interfaces_args val_remote_list_defined_interfaces_args; + remote_list_secrets_args val_remote_list_secrets_args; + remote_secret_lookup_by_uuid_string_args val_remote_secret_lookup_by_uuid_string_args; + remote_secret_define_xml_args val_remote_secret_define_xml_args; + remote_secret_get_xml_desc_args val_remote_secret_get_xml_desc_args; + remote_secret_set_value_args val_remote_secret_set_value_args; + remote_secret_get_value_args val_remote_secret_get_value_args; + remote_secret_undefine_args val_remote_secret_undefine_args; diff --git a/qemud/remote_dispatch_prototypes.h b/qemud/remote_dispatch_prototypes.h index d9f6aad..647f5bb 100644 --- a/qemud/remote_dispatch_prototypes.h +++ b/qemud/remote_dispatch_prototypes.h @@ -513,6 +513,13 @@ static int remoteDispatchListNetworks( remote_error *err, remote_list_networks_args *args, remote_list_networks_ret *ret); +static int remoteDispatchListSecrets( + struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_error *err, + remote_list_secrets_args *args, + remote_list_secrets_ret *ret); static int remoteDispatchListStoragePools( struct qemud_server *server, struct qemud_client *client, @@ -758,6 +765,13 @@ static int remoteDispatchNumOfNetworks( remote_error *err, void *args, remote_num_of_networks_ret *ret); +static int remoteDispatchNumOfSecrets( + struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_error *err, + void *args, + remote_num_of_secrets_ret *ret); static int remoteDispatchNumOfStoragePools( struct qemud_server *server, struct qemud_client *client, @@ -772,6 +786,48 @@ static int remoteDispatchOpen( remote_error *err, remote_open_args *args, void *ret); +static int remoteDispatchSecretDefineXml( + struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_error *err, + remote_secret_define_xml_args *args, + remote_secret_define_xml_ret *ret); +static int remoteDispatchSecretGetValue( + struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_error *err, + remote_secret_get_value_args *args, + remote_secret_get_value_ret *ret); +static int remoteDispatchSecretGetXmlDesc( + struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_error *err, + remote_secret_get_xml_desc_args *args, + remote_secret_get_xml_desc_ret *ret); +static int remoteDispatchSecretLookupByUuidString( + struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_error *err, + remote_secret_lookup_by_uuid_string_args *args, + remote_secret_lookup_by_uuid_string_ret *ret); +static int remoteDispatchSecretSetValue( + struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_error *err, + remote_secret_set_value_args *args, + void *ret); +static int remoteDispatchSecretUndefine( + struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_error *err, + remote_secret_undefine_args *args, + void *ret); static int remoteDispatchStoragePoolBuild( struct qemud_server *server, struct qemud_client *client, diff --git a/qemud/remote_dispatch_ret.h b/qemud/remote_dispatch_ret.h index 5376960..9d74a27 100644 --- a/qemud/remote_dispatch_ret.h +++ b/qemud/remote_dispatch_ret.h @@ -99,3 +99,9 @@ remote_domain_xml_to_native_ret val_remote_domain_xml_to_native_ret; remote_num_of_defined_interfaces_ret val_remote_num_of_defined_interfaces_ret; remote_list_defined_interfaces_ret val_remote_list_defined_interfaces_ret; + remote_num_of_secrets_ret val_remote_num_of_secrets_ret; + remote_list_secrets_ret val_remote_list_secrets_ret; + remote_secret_lookup_by_uuid_string_ret val_remote_secret_lookup_by_uuid_string_ret; + remote_secret_define_xml_ret val_remote_secret_define_xml_ret; + remote_secret_get_xml_desc_ret val_remote_secret_get_xml_desc_ret; + remote_secret_get_value_ret val_remote_secret_get_value_ret; diff --git a/qemud/remote_dispatch_table.h b/qemud/remote_dispatch_table.h index 449786d..02d7bb5 100644 --- a/qemud/remote_dispatch_table.h +++ b/qemud/remote_dispatch_table.h @@ -697,3 +697,43 @@ .args_filter = (xdrproc_t) xdr_remote_list_defined_interfaces_args, .ret_filter = (xdrproc_t) xdr_remote_list_defined_interfaces_ret, }, +{ /* NumOfSecrets => 139 */ + .fn = (dispatch_fn) remoteDispatchNumOfSecrets, + .args_filter = (xdrproc_t) xdr_void, + .ret_filter = (xdrproc_t) xdr_remote_num_of_secrets_ret, +}, +{ /* ListSecrets => 140 */ + .fn = (dispatch_fn) remoteDispatchListSecrets, + .args_filter = (xdrproc_t) xdr_remote_list_secrets_args, + .ret_filter = (xdrproc_t) xdr_remote_list_secrets_ret, +}, +{ /* SecretLookupByUuidString => 141 */ + .fn = (dispatch_fn) remoteDispatchSecretLookupByUuidString, + .args_filter = (xdrproc_t) xdr_remote_secret_lookup_by_uuid_string_args, + .ret_filter = (xdrproc_t) xdr_remote_secret_lookup_by_uuid_string_ret, +}, +{ /* SecretDefineXml => 142 */ + .fn = (dispatch_fn) remoteDispatchSecretDefineXml, + .args_filter = (xdrproc_t) xdr_remote_secret_define_xml_args, + .ret_filter = (xdrproc_t) xdr_remote_secret_define_xml_ret, +}, +{ /* SecretGetXmlDesc => 143 */ + .fn = (dispatch_fn) remoteDispatchSecretGetXmlDesc, + .args_filter = (xdrproc_t) xdr_remote_secret_get_xml_desc_args, + .ret_filter = (xdrproc_t) xdr_remote_secret_get_xml_desc_ret, +}, +{ /* SecretSetValue => 144 */ + .fn = (dispatch_fn) remoteDispatchSecretSetValue, + .args_filter = (xdrproc_t) xdr_remote_secret_set_value_args, + .ret_filter = (xdrproc_t) xdr_void, +}, +{ /* SecretGetValue => 145 */ + .fn = (dispatch_fn) remoteDispatchSecretGetValue, + .args_filter = (xdrproc_t) xdr_remote_secret_get_value_args, + .ret_filter = (xdrproc_t) xdr_remote_secret_get_value_ret, +}, +{ /* SecretUndefine => 146 */ + .fn = (dispatch_fn) remoteDispatchSecretUndefine, + .args_filter = (xdrproc_t) xdr_remote_secret_undefine_args, + .ret_filter = (xdrproc_t) xdr_void, +}, diff --git a/qemud/remote_protocol.c b/qemud/remote_protocol.c index 7b46096..fe7e1e9 100644 --- a/qemud/remote_protocol.c +++ b/qemud/remote_protocol.c @@ -104,6 +104,15 @@ xdr_remote_nonnull_node_device (XDR *xdrs, remote_nonnull_node_device *objp) } bool_t +xdr_remote_nonnull_secret (XDR *xdrs, remote_nonnull_secret *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->uuid)) + return FALSE; + return TRUE; +} + +bool_t xdr_remote_domain (XDR *xdrs, remote_domain *objp) { @@ -2534,6 +2543,129 @@ xdr_remote_domain_xml_to_native_ret (XDR *xdrs, remote_domain_xml_to_native_ret } bool_t +xdr_remote_num_of_secrets_ret (XDR *xdrs, remote_num_of_secrets_ret *objp) +{ + + if (!xdr_int (xdrs, &objp->num)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_list_secrets_args (XDR *xdrs, remote_list_secrets_args *objp) +{ + + if (!xdr_int (xdrs, &objp->maxuuids)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_list_secrets_ret (XDR *xdrs, remote_list_secrets_ret *objp) +{ + char **objp_cpp0 = (char **) (void *) &objp->uuids.uuids_val; + + if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->uuids.uuids_len, REMOTE_SECRET_UUID_LIST_MAX, + sizeof (remote_nonnull_string), (xdrproc_t) xdr_remote_nonnull_string)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_secret_lookup_by_uuid_string_args (XDR *xdrs, remote_secret_lookup_by_uuid_string_args *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->uuid)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_secret_lookup_by_uuid_string_ret (XDR *xdrs, remote_secret_lookup_by_uuid_string_ret *objp) +{ + + if (!xdr_remote_nonnull_secret (xdrs, &objp->secret)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_secret_define_xml_args (XDR *xdrs, remote_secret_define_xml_args *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->xml)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_secret_define_xml_ret (XDR *xdrs, remote_secret_define_xml_ret *objp) +{ + + if (!xdr_remote_nonnull_secret (xdrs, &objp->secret)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_secret_get_xml_desc_args (XDR *xdrs, remote_secret_get_xml_desc_args *objp) +{ + + if (!xdr_remote_nonnull_secret (xdrs, &objp->secret)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_secret_get_xml_desc_ret (XDR *xdrs, remote_secret_get_xml_desc_ret *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->xml)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_secret_set_value_args (XDR *xdrs, remote_secret_set_value_args *objp) +{ + char **objp_cpp0 = (char **) (void *) &objp->value.value_val; + + if (!xdr_remote_nonnull_secret (xdrs, &objp->secret)) + return FALSE; + if (!xdr_bytes (xdrs, objp_cpp0, (u_int *) &objp->value.value_len, REMOTE_SECRET_VALUE_MAX)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_secret_get_value_args (XDR *xdrs, remote_secret_get_value_args *objp) +{ + + if (!xdr_remote_nonnull_secret (xdrs, &objp->secret)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_secret_get_value_ret (XDR *xdrs, remote_secret_get_value_ret *objp) +{ + char **objp_cpp0 = (char **) (void *) &objp->value.value_val; + + if (!xdr_bytes (xdrs, objp_cpp0, (u_int *) &objp->value.value_len, REMOTE_SECRET_VALUE_MAX)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_secret_undefine_args (XDR *xdrs, remote_secret_undefine_args *objp) +{ + + if (!xdr_remote_nonnull_secret (xdrs, &objp->secret)) + return FALSE; + return TRUE; +} + +bool_t xdr_remote_procedure (XDR *xdrs, remote_procedure *objp) { diff --git a/qemud/remote_protocol.h b/qemud/remote_protocol.h index 2e5bc81..d15a01e 100644 --- a/qemud/remote_protocol.h +++ b/qemud/remote_protocol.h @@ -43,6 +43,8 @@ typedef remote_nonnull_string *remote_string; #define REMOTE_SECURITY_MODEL_MAX VIR_SECURITY_MODEL_BUFLEN #define REMOTE_SECURITY_LABEL_MAX VIR_SECURITY_LABEL_BUFLEN #define REMOTE_SECURITY_DOI_MAX VIR_SECURITY_DOI_BUFLEN +#define REMOTE_SECRET_VALUE_MAX 65536 +#define REMOTE_SECRET_UUID_LIST_MAX 16384 typedef char remote_uuid[VIR_UUID_BUFLEN]; @@ -83,6 +85,11 @@ struct remote_nonnull_node_device { }; typedef struct remote_nonnull_node_device remote_nonnull_node_device; +struct remote_nonnull_secret { + remote_nonnull_string uuid; +}; +typedef struct remote_nonnull_secret remote_nonnull_secret; + typedef remote_nonnull_domain *remote_domain; typedef remote_nonnull_network *remote_network; @@ -1427,6 +1434,81 @@ struct remote_domain_xml_to_native_ret { remote_nonnull_string nativeConfig; }; typedef struct remote_domain_xml_to_native_ret remote_domain_xml_to_native_ret; + +struct remote_num_of_secrets_ret { + int num; +}; +typedef struct remote_num_of_secrets_ret remote_num_of_secrets_ret; + +struct remote_list_secrets_args { + int maxuuids; +}; +typedef struct remote_list_secrets_args remote_list_secrets_args; + +struct remote_list_secrets_ret { + struct { + u_int uuids_len; + remote_nonnull_string *uuids_val; + } uuids; +}; +typedef struct remote_list_secrets_ret remote_list_secrets_ret; + +struct remote_secret_lookup_by_uuid_string_args { + remote_nonnull_string uuid; +}; +typedef struct remote_secret_lookup_by_uuid_string_args remote_secret_lookup_by_uuid_string_args; + +struct remote_secret_lookup_by_uuid_string_ret { + remote_nonnull_secret secret; +}; +typedef struct remote_secret_lookup_by_uuid_string_ret remote_secret_lookup_by_uuid_string_ret; + +struct remote_secret_define_xml_args { + remote_nonnull_string xml; +}; +typedef struct remote_secret_define_xml_args remote_secret_define_xml_args; + +struct remote_secret_define_xml_ret { + remote_nonnull_secret secret; +}; +typedef struct remote_secret_define_xml_ret remote_secret_define_xml_ret; + +struct remote_secret_get_xml_desc_args { + remote_nonnull_secret secret; +}; +typedef struct remote_secret_get_xml_desc_args remote_secret_get_xml_desc_args; + +struct remote_secret_get_xml_desc_ret { + remote_nonnull_string xml; +}; +typedef struct remote_secret_get_xml_desc_ret remote_secret_get_xml_desc_ret; + +struct remote_secret_set_value_args { + remote_nonnull_secret secret; + struct { + u_int value_len; + char *value_val; + } value; +}; +typedef struct remote_secret_set_value_args remote_secret_set_value_args; + +struct remote_secret_get_value_args { + remote_nonnull_secret secret; +}; +typedef struct remote_secret_get_value_args remote_secret_get_value_args; + +struct remote_secret_get_value_ret { + struct { + u_int value_len; + char *value_val; + } value; +}; +typedef struct remote_secret_get_value_ret remote_secret_get_value_ret; + +struct remote_secret_undefine_args { + remote_nonnull_secret secret; +}; +typedef struct remote_secret_undefine_args remote_secret_undefine_args; #define REMOTE_PROGRAM 0x20008086 #define REMOTE_PROTOCOL_VERSION 1 @@ -1569,6 +1651,14 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_XML_TO_NATIVE = 136, REMOTE_PROC_NUM_OF_DEFINED_INTERFACES = 137, REMOTE_PROC_LIST_DEFINED_INTERFACES = 138, + REMOTE_PROC_NUM_OF_SECRETS = 139, + REMOTE_PROC_LIST_SECRETS = 140, + REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING = 141, + REMOTE_PROC_SECRET_DEFINE_XML = 142, + REMOTE_PROC_SECRET_GET_XML_DESC = 143, + REMOTE_PROC_SECRET_SET_VALUE = 144, + REMOTE_PROC_SECRET_GET_VALUE = 145, + REMOTE_PROC_SECRET_UNDEFINE = 146, }; typedef enum remote_procedure remote_procedure; @@ -1608,6 +1698,7 @@ extern bool_t xdr_remote_nonnull_interface (XDR *, remote_nonnull_interface*); extern bool_t xdr_remote_nonnull_storage_pool (XDR *, remote_nonnull_storage_pool*); extern bool_t xdr_remote_nonnull_storage_vol (XDR *, remote_nonnull_storage_vol*); extern bool_t xdr_remote_nonnull_node_device (XDR *, remote_nonnull_node_device*); +extern bool_t xdr_remote_nonnull_secret (XDR *, remote_nonnull_secret*); extern bool_t xdr_remote_domain (XDR *, remote_domain*); extern bool_t xdr_remote_network (XDR *, remote_network*); extern bool_t xdr_remote_storage_pool (XDR *, remote_storage_pool*); @@ -1831,6 +1922,19 @@ extern bool_t xdr_remote_domain_xml_from_native_args (XDR *, remote_domain_xml_ extern bool_t xdr_remote_domain_xml_from_native_ret (XDR *, remote_domain_xml_from_native_ret*); extern bool_t xdr_remote_domain_xml_to_native_args (XDR *, remote_domain_xml_to_native_args*); extern bool_t xdr_remote_domain_xml_to_native_ret (XDR *, remote_domain_xml_to_native_ret*); +extern bool_t xdr_remote_num_of_secrets_ret (XDR *, remote_num_of_secrets_ret*); +extern bool_t xdr_remote_list_secrets_args (XDR *, remote_list_secrets_args*); +extern bool_t xdr_remote_list_secrets_ret (XDR *, remote_list_secrets_ret*); +extern bool_t xdr_remote_secret_lookup_by_uuid_string_args (XDR *, remote_secret_lookup_by_uuid_string_args*); +extern bool_t xdr_remote_secret_lookup_by_uuid_string_ret (XDR *, remote_secret_lookup_by_uuid_string_ret*); +extern bool_t xdr_remote_secret_define_xml_args (XDR *, remote_secret_define_xml_args*); +extern bool_t xdr_remote_secret_define_xml_ret (XDR *, remote_secret_define_xml_ret*); +extern bool_t xdr_remote_secret_get_xml_desc_args (XDR *, remote_secret_get_xml_desc_args*); +extern bool_t xdr_remote_secret_get_xml_desc_ret (XDR *, remote_secret_get_xml_desc_ret*); +extern bool_t xdr_remote_secret_set_value_args (XDR *, remote_secret_set_value_args*); +extern bool_t xdr_remote_secret_get_value_args (XDR *, remote_secret_get_value_args*); +extern bool_t xdr_remote_secret_get_value_ret (XDR *, remote_secret_get_value_ret*); +extern bool_t xdr_remote_secret_undefine_args (XDR *, remote_secret_undefine_args*); extern bool_t xdr_remote_procedure (XDR *, remote_procedure*); extern bool_t xdr_remote_message_type (XDR *, remote_message_type*); extern bool_t xdr_remote_message_status (XDR *, remote_message_status*); @@ -1846,6 +1950,7 @@ extern bool_t xdr_remote_nonnull_interface (); extern bool_t xdr_remote_nonnull_storage_pool (); extern bool_t xdr_remote_nonnull_storage_vol (); extern bool_t xdr_remote_nonnull_node_device (); +extern bool_t xdr_remote_nonnull_secret (); extern bool_t xdr_remote_domain (); extern bool_t xdr_remote_network (); extern bool_t xdr_remote_storage_pool (); @@ -2069,6 +2174,19 @@ extern bool_t xdr_remote_domain_xml_from_native_args (); extern bool_t xdr_remote_domain_xml_from_native_ret (); extern bool_t xdr_remote_domain_xml_to_native_args (); extern bool_t xdr_remote_domain_xml_to_native_ret (); +extern bool_t xdr_remote_num_of_secrets_ret (); +extern bool_t xdr_remote_list_secrets_args (); +extern bool_t xdr_remote_list_secrets_ret (); +extern bool_t xdr_remote_secret_lookup_by_uuid_string_args (); +extern bool_t xdr_remote_secret_lookup_by_uuid_string_ret (); +extern bool_t xdr_remote_secret_define_xml_args (); +extern bool_t xdr_remote_secret_define_xml_ret (); +extern bool_t xdr_remote_secret_get_xml_desc_args (); +extern bool_t xdr_remote_secret_get_xml_desc_ret (); +extern bool_t xdr_remote_secret_set_value_args (); +extern bool_t xdr_remote_secret_get_value_args (); +extern bool_t xdr_remote_secret_get_value_ret (); +extern bool_t xdr_remote_secret_undefine_args (); extern bool_t xdr_remote_procedure (); extern bool_t xdr_remote_message_type (); extern bool_t xdr_remote_message_status (); diff --git a/qemud/remote_protocol.x b/qemud/remote_protocol.x index 8f9b6db..8f4b864 100644 --- a/qemud/remote_protocol.x +++ b/qemud/remote_protocol.x @@ -136,6 +136,16 @@ const REMOTE_SECURITY_LABEL_MAX = VIR_SECURITY_LABEL_BUFLEN; */ const REMOTE_SECURITY_DOI_MAX = VIR_SECURITY_DOI_BUFLEN; +/* + * Maximum size of a secret value. + */ +const REMOTE_SECRET_VALUE_MAX = 65536; + +/* + * Upper limit on list of secrets. + */ +const REMOTE_SECRET_UUID_LIST_MAX = 16384; + /* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */ typedef opaque remote_uuid[VIR_UUID_BUFLEN]; @@ -176,6 +186,11 @@ struct remote_nonnull_node_device { remote_nonnull_string name; }; +/* A secret which may not be null. */ +struct remote_nonnull_secret { + remote_nonnull_string uuid; +}; + /* A domain or network which may be NULL. */ typedef remote_nonnull_domain *remote_domain; typedef remote_nonnull_network *remote_network; @@ -1266,6 +1281,59 @@ struct remote_domain_xml_to_native_ret { }; +struct remote_num_of_secrets_ret { + int num; +}; + +struct remote_list_secrets_args { + int maxuuids; +}; + +struct remote_list_secrets_ret { + remote_nonnull_string uuids<REMOTE_SECRET_UUID_LIST_MAX>; +}; + +struct remote_secret_lookup_by_uuid_string_args { + remote_nonnull_string uuid; +}; + +struct remote_secret_lookup_by_uuid_string_ret { + remote_nonnull_secret secret; +}; + +struct remote_secret_define_xml_args { + remote_nonnull_string xml; +}; + +struct remote_secret_define_xml_ret { + remote_nonnull_secret secret; +}; + +struct remote_secret_get_xml_desc_args { + remote_nonnull_secret secret; +}; + +struct remote_secret_get_xml_desc_ret { + remote_nonnull_string xml; +}; + +struct remote_secret_set_value_args { + remote_nonnull_secret secret; + opaque value<REMOTE_SECRET_VALUE_MAX>; +}; + +struct remote_secret_get_value_args { + remote_nonnull_secret secret; +}; + +struct remote_secret_get_value_ret { + opaque value<REMOTE_SECRET_VALUE_MAX>; +}; + +struct remote_secret_undefine_args { + remote_nonnull_secret secret; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -1424,7 +1492,16 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_XML_TO_NATIVE = 136, REMOTE_PROC_NUM_OF_DEFINED_INTERFACES = 137, - REMOTE_PROC_LIST_DEFINED_INTERFACES = 138 + REMOTE_PROC_LIST_DEFINED_INTERFACES = 138, + + REMOTE_PROC_NUM_OF_SECRETS = 139, + REMOTE_PROC_LIST_SECRETS = 140, + REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING = 141, + REMOTE_PROC_SECRET_DEFINE_XML = 142, + REMOTE_PROC_SECRET_GET_XML_DESC = 143, + REMOTE_PROC_SECRET_SET_VALUE = 144, + REMOTE_PROC_SECRET_GET_VALUE = 145, + REMOTE_PROC_SECRET_UNDEFINE = 146 }; -- 1.6.2.5

Changes since the second submission: - Update for the changed public API - s/secret_id/uuid/g - use "unsigned char *" for secret value --- src/datatypes.h | 1 + src/remote_internal.c | 323 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 324 insertions(+), 0 deletions(-) diff --git a/src/datatypes.h b/src/datatypes.h index 56c3777..aa60b63 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -140,6 +140,7 @@ struct _virConnect { void * interfacePrivateData; void * storagePrivateData; void * devMonPrivateData; + void * secretPrivateData; /* * The lock mutex must be acquired before accessing/changing diff --git a/src/remote_internal.c b/src/remote_internal.c index a58b768..d661fe2 100644 --- a/src/remote_internal.c +++ b/src/remote_internal.c @@ -221,11 +221,13 @@ static virInterfacePtr get_nonnull_interface (virConnectPtr conn, remote_nonnull static virStoragePoolPtr get_nonnull_storage_pool (virConnectPtr conn, remote_nonnull_storage_pool pool); static virStorageVolPtr get_nonnull_storage_vol (virConnectPtr conn, remote_nonnull_storage_vol vol); static virNodeDevicePtr get_nonnull_node_device (virConnectPtr conn, remote_nonnull_node_device dev); +static virSecretPtr get_nonnull_secret (virConnectPtr conn, remote_nonnull_secret secret); static void make_nonnull_domain (remote_nonnull_domain *dom_dst, virDomainPtr dom_src); static void make_nonnull_network (remote_nonnull_network *net_dst, virNetworkPtr net_src); static void make_nonnull_interface (remote_nonnull_interface *interface_dst, virInterfacePtr interface_src); static void make_nonnull_storage_pool (remote_nonnull_storage_pool *pool_dst, virStoragePoolPtr vol_src); static void make_nonnull_storage_vol (remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src); +static void make_nonnull_secret (remote_nonnull_secret *secret_dst, virSecretPtr secret_src); void remoteDomainEventFired(int watch, int fd, int event, void *data); static void remoteDomainQueueEvent(virConnectPtr conn, XDR *xdr); void remoteDomainEventQueueFlush(int timer, void *opaque); @@ -6319,6 +6321,300 @@ done: return rv; } +static virDrvOpenStatus +remoteSecretOpen (virConnectPtr conn, + virConnectAuthPtr auth, + int flags) +{ + if (inside_daemon) + return VIR_DRV_OPEN_DECLINED; + + if (conn && + conn->driver && + STREQ (conn->driver->name, "remote")) { + struct private_data *priv; + + /* If we're here, the remote driver is already + * in use due to a) a QEMU uri, or b) a remote + * URI. So we can re-use existing connection + */ + priv = conn->privateData; + remoteDriverLock(priv); + priv->localUses++; + conn->secretPrivateData = priv; + remoteDriverUnlock(priv); + return VIR_DRV_OPEN_SUCCESS; + } else if (conn->networkDriver && + STREQ (conn->networkDriver->name, "remote")) { + struct private_data *priv = conn->networkPrivateData; + remoteDriverLock(priv); + conn->secretPrivateData = priv; + priv->localUses++; + remoteDriverUnlock(priv); + return VIR_DRV_OPEN_SUCCESS; + } else { + /* Using a non-remote driver, so we need to open a + * new connection for secret APIs, forcing it to + * use the UNIX transport. + */ + struct private_data *priv; + int ret; + ret = remoteOpenSecondaryDriver(conn, + auth, + flags, + &priv); + if (ret == VIR_DRV_OPEN_SUCCESS) + conn->secretPrivateData = priv; + return ret; + } +} + +static int +remoteSecretClose (virConnectPtr conn) +{ + int rv = 0; + struct private_data *priv = conn->secretPrivateData; + + conn->secretPrivateData = NULL; + remoteDriverLock(priv); + priv->localUses--; + if (!priv->localUses) { + rv = doRemoteClose(conn, priv); + remoteDriverUnlock(priv); + virMutexDestroy(&priv->lock); + VIR_FREE(priv); + } + if (priv) + remoteDriverUnlock(priv); + return rv; +} + +static int +remoteSecretNumOfSecrets (virConnectPtr conn) +{ + int rv = -1; + remote_num_of_secrets_ret ret; + struct private_data *priv = conn->secretPrivateData; + + remoteDriverLock (priv); + + memset (&ret, 0, sizeof (ret)); + if (call (conn, priv, 0, REMOTE_PROC_NUM_OF_SECRETS, + (xdrproc_t) xdr_void, (char *) NULL, + (xdrproc_t) xdr_remote_num_of_secrets_ret, (char *) &ret) == -1) + goto done; + + rv = ret.num; + +done: + remoteDriverUnlock (priv); + return rv; +} + +static int +remoteSecretListSecrets (virConnectPtr conn, char **uuids, int maxuuids) +{ + int rv = -1; + int i; + remote_list_secrets_args args; + remote_list_secrets_ret ret; + struct private_data *priv = conn->secretPrivateData; + + remoteDriverLock(priv); + + if (maxuuids > REMOTE_SECRET_UUID_LIST_MAX) { + errorf (conn, VIR_ERR_RPC, _("too many remote secret UUIDs: %d > %d"), + maxuuids, REMOTE_SECRET_UUID_LIST_MAX); + goto done; + } + args.maxuuids = maxuuids; + + memset (&ret, 0, sizeof ret); + if (call (conn, priv, 0, REMOTE_PROC_LIST_SECRETS, + (xdrproc_t) xdr_remote_list_secrets_args, (char *) &args, + (xdrproc_t) xdr_remote_list_secrets_ret, (char *) &ret) == -1) + goto done; + + if (ret.uuids.uuids_len > maxuuids) { + errorf (conn, VIR_ERR_RPC, _("too many remote secret UUIDs: %d > %d"), + ret.uuids.uuids_len, maxuuids); + goto cleanup; + } + + /* This call is caller-frees. However xdr_free will free up both the + * names and the list of pointers, so we have to strdup the + * names here. + */ + for (i = 0; i < ret.uuids.uuids_len; ++i) + uuids[i] = strdup (ret.uuids.uuids_val[i]); + + rv = ret.uuids.uuids_len; + +cleanup: + xdr_free ((xdrproc_t) xdr_remote_list_secrets_ret, (char *) &ret); + +done: + remoteDriverUnlock(priv); + return rv; +} + +static virSecretPtr +remoteSecretLookupByUUIDString (virConnectPtr conn, const char *uuid) +{ + virSecretPtr rv = NULL; + remote_secret_lookup_by_uuid_string_args args; + remote_secret_lookup_by_uuid_string_ret ret; + struct private_data *priv = conn->secretPrivateData; + + remoteDriverLock (priv); + + args.uuid = (char *) uuid; + + memset (&ret, 0, sizeof (ret)); + if (call (conn, priv, 0, REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING, + (xdrproc_t) xdr_remote_secret_lookup_by_uuid_string_args, (char *) &args, + (xdrproc_t) xdr_remote_secret_lookup_by_uuid_string_ret, (char *) &ret) == -1) + goto done; + + rv = get_nonnull_secret (conn, ret.secret); + xdr_free ((xdrproc_t) xdr_remote_secret_lookup_by_uuid_string_ret, + (char *) &ret); + +done: + remoteDriverUnlock (priv); + return rv; +} + +static virSecretPtr +remoteSecretDefineXML (virConnectPtr conn, const char *xml) +{ + virSecretPtr rv = NULL; + remote_secret_define_xml_args args; + remote_secret_lookup_by_uuid_string_ret ret; + struct private_data *priv = conn->secretPrivateData; + + remoteDriverLock (priv); + + args.xml = (char *) xml; + + memset (&ret, 0, sizeof (ret)); + if (call (conn, priv, 0, REMOTE_PROC_SECRET_DEFINE_XML, + (xdrproc_t) xdr_remote_secret_define_xml_args, (char *) &args, + (xdrproc_t) xdr_remote_secret_define_xml_ret, (char *) &ret) == -1) + goto done; + + rv = get_nonnull_secret (conn, ret.secret); + xdr_free ((xdrproc_t) xdr_remote_secret_lookup_by_uuid_string_ret, + (char *) &ret); + +done: + remoteDriverUnlock (priv); + return rv; +} + +static char * +remoteSecretGetXMLDesc (virSecretPtr secret) +{ + char *rv = NULL; + remote_secret_get_xml_desc_args args; + remote_secret_get_xml_desc_ret ret; + struct private_data *priv = secret->conn->secretPrivateData; + + remoteDriverLock (priv); + + make_nonnull_secret (&args.secret, secret); + + memset (&ret, 0, sizeof (ret)); + if (call (secret->conn, priv, 0, REMOTE_PROC_SECRET_GET_XML_DESC, + (xdrproc_t) xdr_remote_secret_get_xml_desc_args, (char *) &args, + (xdrproc_t) xdr_remote_secret_get_xml_desc_ret, (char *) &ret) == -1) + goto done; + + /* Caller frees. */ + rv = ret.xml; + +done: + remoteDriverUnlock (priv); + return rv; +} + +static int +remoteSecretSetValue (virSecretPtr secret, const unsigned char *value, + size_t value_size) +{ + int rv = -1; + remote_secret_set_value_args args; + struct private_data *priv = secret->conn->secretPrivateData; + + remoteDriverLock (priv); + + make_nonnull_secret (&args.secret, secret); + args.value.value_len = value_size; + args.value.value_val = (char *) value; + + if (call (secret->conn, priv, 0, REMOTE_PROC_SECRET_SET_VALUE, + (xdrproc_t) xdr_remote_secret_set_value_args, (char *) &args, + (xdrproc_t) xdr_void, (char *) NULL) == -1) + goto done; + + rv = 0; + +done: + remoteDriverUnlock (priv); + return rv; +} + +static unsigned char * +remoteSecretGetValue (virSecretPtr secret, size_t *value_size, + /* If the call goes over a socket, it's not internal */ + bool libvirt_internal_call ATTRIBUTE_UNUSED) +{ + unsigned char *rv = NULL; + remote_secret_get_value_args args; + remote_secret_get_value_ret ret; + struct private_data *priv = secret->conn->secretPrivateData; + + remoteDriverLock (priv); + + make_nonnull_secret (&args.secret, secret); + + memset (&ret, 0, sizeof (ret)); + if (call (secret->conn, priv, 0, REMOTE_PROC_SECRET_GET_VALUE, + (xdrproc_t) xdr_remote_secret_get_value_args, (char *) &args, + (xdrproc_t) xdr_remote_secret_get_value_ret, (char *) &ret) == -1) + goto done; + + *value_size = ret.value.value_len; + rv = (unsigned char *) ret.value.value_val; /* Caller frees. */ + +done: + remoteDriverUnlock (priv); + return rv; +} + +static int +remoteSecretUndefine (virSecretPtr secret) +{ + int rv = -1; + remote_secret_undefine_args args; + struct private_data *priv = secret->conn->secretPrivateData; + + remoteDriverLock (priv); + + make_nonnull_secret (&args.secret, secret); + + if (call (secret->conn, priv, 0, REMOTE_PROC_SECRET_UNDEFINE, + (xdrproc_t) xdr_remote_secret_undefine_args, (char *) &args, + (xdrproc_t) xdr_void, (char *) NULL) == -1) + goto done; + + rv = 0; + +done: + remoteDriverUnlock (priv); + return rv; +} + /*----------------------------------------------------------------------*/ @@ -7415,6 +7711,12 @@ get_nonnull_node_device (virConnectPtr conn, remote_nonnull_node_device dev) return virGetNodeDevice(conn, dev.name); } +static virSecretPtr +get_nonnull_secret (virConnectPtr conn, remote_nonnull_secret secret) +{ + return virGetSecret(conn, secret.uuid); +} + /* Make remote_nonnull_domain and remote_nonnull_network. */ static void make_nonnull_domain (remote_nonnull_domain *dom_dst, virDomainPtr dom_src) @@ -7454,6 +7756,12 @@ make_nonnull_storage_vol (remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_dst->key = vol_src->key; } +static void +make_nonnull_secret (remote_nonnull_secret *secret_dst, virSecretPtr secret_src) +{ + secret_dst->uuid = secret_src->uuid; +} + /*----------------------------------------------------------------------*/ unsigned long remoteVersion(void) @@ -7607,6 +7915,20 @@ static virStorageDriver storage_driver = { .volGetPath = remoteStorageVolGetPath, }; +static virSecretDriver secret_driver = { + .name = "remote", + .open = remoteSecretOpen, + .close = remoteSecretClose, + .numOfSecrets = remoteSecretNumOfSecrets, + .listSecrets = remoteSecretListSecrets, + .lookupByUUIDString = remoteSecretLookupByUUIDString, + .defineXML = remoteSecretDefineXML, + .getXMLDesc = remoteSecretGetXMLDesc, + .setValue = remoteSecretSetValue, + .getValue = remoteSecretGetValue, + .undefine = remoteSecretUndefine +}; + static virDeviceMonitor dev_monitor = { .name = "remote", .open = remoteDevMonOpen, @@ -7644,6 +7966,7 @@ remoteRegister (void) if (virRegisterInterfaceDriver (&interface_driver) == -1) return -1; if (virRegisterStorageDriver (&storage_driver) == -1) return -1; if (virRegisterDeviceMonitor (&dev_monitor) == -1) return -1; + if (virRegisterSecretDriver (&secret_driver) == -1) return -1; #ifdef WITH_LIBVIRTD if (virRegisterStateDriver (&state_driver) == -1) return -1; #endif -- 1.6.2.5

On Sun, Aug 16, 2009 at 10:47:58PM +0200, Miloslav Trmač wrote:
Changes since the second submission: - Update for the changed public API - s/secret_id/uuid/g - use "unsigned char *" for secret value --- src/datatypes.h | 1 + src/remote_internal.c | 323 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 324 insertions(+), 0 deletions(-) [...] +static virDrvOpenStatus +remoteSecretOpen (virConnectPtr conn, + virConnectAuthPtr auth, + int flags) +{ + if (inside_daemon) + return VIR_DRV_OPEN_DECLINED; + + if (conn && + conn->driver && + STREQ (conn->driver->name, "remote")) { + struct private_data *priv; + + /* If we're here, the remote driver is already + * in use due to a) a QEMU uri, or b) a remote + * URI. So we can re-use existing connection + */
Hum, is that comment right ? We are certainly using a remote URI in any case there, isn't it ? The driver looks fine, everything is synchronous but none of those operations should be blocking in any way, ACK Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Changes since the second submission: - Update for the changed public API - s/secret_id/uuid/g - use "unsigned char *" for secret value --- qemud/remote.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 203 insertions(+), 0 deletions(-) diff --git a/qemud/remote.c b/qemud/remote.c index d32d513..c66f321 100644 --- a/qemud/remote.c +++ b/qemud/remote.c @@ -64,12 +64,14 @@ static virNetworkPtr get_nonnull_network (virConnectPtr conn, remote_nonnull_net static virInterfacePtr get_nonnull_interface (virConnectPtr conn, remote_nonnull_interface iface); static virStoragePoolPtr get_nonnull_storage_pool (virConnectPtr conn, remote_nonnull_storage_pool pool); static virStorageVolPtr get_nonnull_storage_vol (virConnectPtr conn, remote_nonnull_storage_vol vol); +static virSecretPtr get_nonnull_secret (virConnectPtr conn, remote_nonnull_secret secret); static void make_nonnull_domain (remote_nonnull_domain *dom_dst, virDomainPtr dom_src); static void make_nonnull_network (remote_nonnull_network *net_dst, virNetworkPtr net_src); static void make_nonnull_interface (remote_nonnull_interface *interface_dst, virInterfacePtr interface_src); static void make_nonnull_storage_pool (remote_nonnull_storage_pool *pool_dst, virStoragePoolPtr pool_src); static void make_nonnull_storage_vol (remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src); static void make_nonnull_node_device (remote_nonnull_node_device *dev_dst, virNodeDevicePtr dev_src); +static void make_nonnull_secret (remote_nonnull_secret *secret_dst, virSecretPtr secret_src); #include "remote_dispatch_prototypes.h" @@ -4515,6 +4517,195 @@ error: VIR_FREE(msg); } +static int +remoteDispatchNumOfSecrets (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, remote_error *err, + void *args ATTRIBUTE_UNUSED, + remote_num_of_secrets_ret *ret) +{ + ret->num = virConnectNumOfSecrets (conn); + if (ret->num == -1) { + remoteDispatchConnError (err, conn); + return -1; + } + + return 0; +} + +static int +remoteDispatchListSecrets (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, remote_error *err, + remote_list_secrets_args *args, + remote_list_secrets_ret *ret) +{ + if (args->maxuuids > REMOTE_SECRET_UUID_LIST_MAX) { + remoteDispatchFormatError (err, "%s", + _("maxuuids > REMOTE_SECRET_UUID_LIST_MAX")); + return -1; + } + + if (VIR_ALLOC_N (ret->uuids.uuids_val, args->maxuuids) < 0) { + remoteDispatchOOMError (err); + return -1; + } + + ret->uuids.uuids_len = virConnectListSecrets (conn, ret->uuids.uuids_val, + args->maxuuids); + if (ret->uuids.uuids_len == -1) { + VIR_FREE (ret->uuids.uuids_val); + remoteDispatchConnError (err, conn); + return -1; + } + + return 0; +} + +static int +remoteDispatchSecretDefineXml (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, remote_error *err, + remote_secret_define_xml_args *args, + remote_secret_define_xml_ret *ret) +{ + virSecretPtr secret; + + secret = virSecretDefineXML (conn, args->xml); + if (secret == NULL) { + remoteDispatchConnError (err, conn); + return -1; + } + + make_nonnull_secret (&ret->secret, secret); + virSecretFree (secret); + return 0; +} + +static int +remoteDispatchSecretGetValue (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, remote_error *err, + remote_secret_get_value_args *args, + remote_secret_get_value_ret *ret) +{ + virSecretPtr secret; + size_t value_size; + unsigned char *value; + + secret = get_nonnull_secret (conn, args->secret); + if (secret == NULL) { + remoteDispatchConnError (err, conn); + return -1; + } + + value = virSecretGetValue (secret, &value_size); + if (value == NULL) { + remoteDispatchConnError (err, conn); + virSecretFree(secret); + return -1; + } + + ret->value.value_len = value_size; + ret->value.value_val = (char *)value; + virSecretFree(secret); + return 0; +} + +static int +remoteDispatchSecretGetXmlDesc (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, remote_error *err, + remote_secret_get_xml_desc_args *args, + remote_secret_get_xml_desc_ret *ret) +{ + virSecretPtr secret; + + secret = get_nonnull_secret (conn, args->secret); + if (secret == NULL) { + remoteDispatchConnError (err, conn); + return -1; + } + ret->xml = virSecretGetXMLDesc (secret); + if (ret->xml == NULL) { + remoteDispatchConnError (err, conn); + virSecretFree(secret); + return -1; + } + virSecretFree(secret); + return 0; +} + +static int +remoteDispatchSecretLookupByUuidString (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, remote_error *err, + remote_secret_lookup_by_uuid_string_args *args, + remote_secret_lookup_by_uuid_string_ret *ret) +{ + virSecretPtr secret; + + secret = virSecretLookupByUUIDString (conn, args->uuid); + if (secret == NULL) { + remoteDispatchConnError (err, conn); + return -1; + } + + make_nonnull_secret (&ret->secret, secret); + virSecretFree (secret); + return 0; +} + +static int +remoteDispatchSecretSetValue (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, remote_error *err, + remote_secret_set_value_args *args, + void *ret ATTRIBUTE_UNUSED) +{ + virSecretPtr secret; + + secret = get_nonnull_secret (conn, args->secret); + if (secret == NULL) { + remoteDispatchConnError (err, conn); + return -1; + } + if (virSecretSetValue (secret, (const unsigned char *)args->value.value_val, + args->value.value_len) < 0) { + remoteDispatchConnError (err, conn); + virSecretFree(secret); + return -1; + } + + virSecretFree(secret); + return 0; +} + +static int +remoteDispatchSecretUndefine (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, remote_error *err, + remote_secret_undefine_args *args, + void *ret ATTRIBUTE_UNUSED) +{ + virSecretPtr secret; + + secret = get_nonnull_secret (conn, args->secret); + if (secret == NULL) { + remoteDispatchConnError (err, conn); + return -1; + } + if (virSecretUndefine (secret) < 0) { + remoteDispatchConnError (err, conn); + virSecretFree(secret); + return -1; + } + + virSecretFree(secret); + return 0; +} + + /*----- Helpers. -----*/ /* get_nonnull_domain and get_nonnull_network turn an on-wire @@ -4561,6 +4752,12 @@ get_nonnull_storage_vol (virConnectPtr conn, remote_nonnull_storage_vol vol) return ret; } +static virSecretPtr +get_nonnull_secret (virConnectPtr conn, remote_nonnull_secret secret) +{ + return virGetSecret (conn, secret.uuid); +} + /* Make remote_nonnull_domain and remote_nonnull_network. */ static void make_nonnull_domain (remote_nonnull_domain *dom_dst, virDomainPtr dom_src) @@ -4605,3 +4802,9 @@ make_nonnull_node_device (remote_nonnull_node_device *dev_dst, virNodeDevicePtr { dev_dst->name = strdup(dev_src->name); } + +static void +make_nonnull_secret (remote_nonnull_secret *secret_dst, virSecretPtr secret_src) +{ + secret_dst->uuid = strdup(secret_src->uuid); +} -- 1.6.2.5

On Sun, Aug 16, 2009 at 10:47:59PM +0200, Miloslav Trmač wrote:
Changes since the second submission: - Update for the changed public API - s/secret_id/uuid/g - use "unsigned char *" for secret value
like for 04/20 , this will need some regeneration for the new flags args but otherwise fine Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

This implementation stores the secrets in an unencrypted text file, for simplicity in implementation and debugging. (Symmetric encryption, e.g. using gpgme, will not be difficult to add. Because the TLS private key used by libvirtd is stored unencrypted, encrypting the secrets file does not currently provide much additional security.) Changes since the second submission: - Update for the changed internal API - Fix some memory leaks - Use a clearer error message in secretGetValue() - s/secret_id/uuid/g - Use "unsigned char *" for secret value --- include/libvirt/virterror.h | 1 + po/POTFILES.in | 1 + qemud/qemud.c | 3 + src/Makefile.am | 14 + src/libvirt_private.syms | 2 + src/secret_driver.c | 1102 +++++++++++++++++++++++++++++++++++++++++++ src/secret_driver.h | 28 ++ src/test.c | 21 + src/virterror.c | 5 + 9 files changed, 1177 insertions(+), 0 deletions(-) create mode 100644 src/secret_driver.c create mode 100644 src/secret_driver.h diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index 62cad88..fa5cac4 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -169,6 +169,7 @@ typedef enum { VIR_ERR_MULTIPLE_INTERFACES, /* more than one matching interface found */ VIR_WAR_NO_SECRET, /* failed to start secret storage */ VIR_ERR_INVALID_SECRET, /* invalid secret */ + VIR_ERR_NO_SECRET, /* secret not found */ } virErrorNumber; /** diff --git a/po/POTFILES.in b/po/POTFILES.in index 66d3ebd..e9d388a 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -30,6 +30,7 @@ src/proxy_internal.c src/qemu_conf.c src/qemu_driver.c src/remote_internal.c +src/secret_driver.c src/security.c src/security_selinux.c src/storage_backend.c diff --git a/qemud/qemud.c b/qemud/qemud.c index e657cf2..ec7c021 100644 --- a/qemud/qemud.c +++ b/qemud/qemud.c @@ -92,6 +92,7 @@ #ifdef WITH_NODE_DEVICES #include "node_device.h" #endif +#include "secret_driver.h" #endif @@ -814,6 +815,7 @@ static struct qemud_server *qemudInitialize(int sigread) { virDriverLoadModule("network"); virDriverLoadModule("storage"); virDriverLoadModule("nodedev"); + virDriverLoadModule("secret"); virDriverLoadModule("qemu"); virDriverLoadModule("lxc"); virDriverLoadModule("uml"); @@ -832,6 +834,7 @@ static struct qemud_server *qemudInitialize(int sigread) { (defined(HAVE_HAL) || defined(HAVE_DEVKIT)) nodedevRegister(); #endif + secretRegister(); #ifdef WITH_QEMU qemuRegister(); #endif diff --git a/src/Makefile.am b/src/Makefile.am index 9567490..ce33695 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -176,6 +176,9 @@ NETWORK_DRIVER_SOURCES = \ INTERFACE_DRIVER_SOURCES = \ interface_driver.h interface_driver.c +SECRET_DRIVER_SOURCES = \ + secret_driver.h secret_driver.c + # Storage backend specific impls STORAGE_DRIVER_SOURCES = \ storage_driver.h storage_driver.c \ @@ -448,6 +451,17 @@ endif libvirt_driver_interface_la_SOURCES = $(INTERFACE_DRIVER_SOURCES) endif +if WITH_DRIVER_MODULES +mod_LTLIBRARIES += libvirt_driver_secret.la +else +noinst_LTLIBRARIES += libvirt_driver_secret.la +libvirt_la_LIBADD += libvirt_driver_secret.la +endif +if WITH_DRIVER_MODULES +libvirt_driver_secret_la_LDFLAGS = -module -avoid-version +endif +libvirt_driver_secret_la_SOURCES = $(SECRET_DRIVER_SOURCES) + # Needed to keep automake quiet about conditionals libvirt_driver_storage_la_SOURCES = if WITH_STORAGE_DIR diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 61f18e6..dd691be 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -295,6 +295,8 @@ qparam_get_query; qparam_query_parse; free_qparam_set; +# secret.h +secretRegister; # security.h virSecurityDriverVerify; diff --git a/src/secret_driver.c b/src/secret_driver.c new file mode 100644 index 0000000..d9e638c --- /dev/null +++ b/src/secret_driver.c @@ -0,0 +1,1102 @@ +/* + * secret_driver.c: local driver for secret manipulation API + * + * Copyright (C) 2009 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Red Hat Author: Miloslav Trmač <mitr@redhat.com> + */ + +#include <config.h> + +#include <fcntl.h> +#include <stdbool.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "internal.h" +#include "base64.h" +#include "buf.h" +#include "datatypes.h" +#include "driver.h" +#include "memory.h" +#include "secret_driver.h" +#include "threads.h" +#include "util.h" +#include "uuid.h" +#include "virterror_internal.h" +#include "xml.h" + +#define VIR_FROM_THIS VIR_FROM_SECRET + +#define virSecretReportError(conn, code, fmt...) \ + virReportErrorHelper(conn, VIR_FROM_SECRET, code, __FILE__, \ + __FUNCTION__, __LINE__, fmt) + +#define secretLog(msg...) fprintf(stderr, msg) + +typedef struct _virSecretEntry virSecretEntry; +typedef virSecretEntry *virSecretEntryPtr; +struct _virSecretEntry { + virSecretEntryPtr next; + char *id; /* We generate UUIDs, but don't restrict user-chosen IDs */ + unsigned char *value; /* May be NULL */ + size_t value_size; + unsigned ephemeral : 1; + unsigned private : 1; + char *description, *volume; /* May be NULL */ +}; + +typedef struct _virSecretDriverState virSecretDriverState; +typedef virSecretDriverState *virSecretDriverStatePtr; +struct _virSecretDriverState { + virMutex lock; + virSecretEntry *secrets; + char *filename; +}; + +static virSecretDriverStatePtr driverState; + +static void +secretDriverLock(virSecretDriverStatePtr driver) +{ + virMutexLock(&driver->lock); +} + +static void +secretDriverUnlock(virSecretDriverStatePtr driver) +{ + virMutexUnlock(&driver->lock); +} + +static virSecretEntryPtr +listUnlink(virSecretEntryPtr *pptr) +{ + virSecretEntryPtr secret; + + secret = *pptr; + *pptr = secret->next; + return secret; +} + +static void +listInsert(virSecretEntryPtr *pptr, virSecretEntryPtr secret) +{ + secret->next = *pptr; + *pptr = secret; +} + +static void +secretFree(virSecretEntryPtr secret) +{ + if (secret == NULL) + return; + + VIR_FREE(secret->id); + if (secret->value != NULL) { + memset(secret->value, 0, secret->value_size); + VIR_FREE(secret->value); + } + VIR_FREE(secret->description); + VIR_FREE(secret->volume); + VIR_FREE(secret); +} + +static virSecretEntryPtr * +secretFind(virSecretDriverStatePtr driver, const char *uuid) +{ + virSecretEntryPtr *pptr, s; + + for (pptr = &driver->secrets; (s = *pptr) != NULL; pptr = &s->next) { + if (STREQ(s->id, uuid)) + return pptr; + } + return NULL; +} + +static virSecretEntryPtr +secretCreate(virConnectPtr conn, virSecretDriverStatePtr driver, + const char *uuid) +{ + virSecretEntryPtr secret = NULL; + + if (VIR_ALLOC(secret) < 0) + goto no_memory; + secret->id = strdup(uuid); + if (secret->id == NULL) + goto no_memory; + listInsert(&driver->secrets, secret); + return secret; + + no_memory: + virReportOOMError(conn); + secretFree(secret); + return NULL; +} + +static virSecretEntryPtr +secretFindOrCreate(virConnectPtr conn, virSecretDriverStatePtr driver, + const char *uuid, bool *created_new) +{ + virSecretEntryPtr *pptr, secret; + + pptr = secretFind(driver, uuid); + if (pptr != NULL) { + if (created_new != NULL) + *created_new = false; + return *pptr; + } + + secret = secretCreate(conn, driver, uuid); + if (secret != NULL && created_new != NULL) + *created_new = true; + return secret; +} + +/* The secret storage file format is intentionally simplistic, in order to + minimize the number of copies of unencrypted secrets in memory. */ + +static int +writeString(virConnectPtr conn, int fd, const char *s) +{ + int ret; + + ret = safewrite(fd, s, strlen(s)); + if (ret < 0) + virReportSystemError (conn, errno, "%s", + _("cannot write secrets file")); + return ret; +} + +static int +writeBase64Data(virConnectPtr conn, int fd, const char *field, + const void *data, size_t size) +{ + int ret = -1; + char *base64 = NULL; + + if (writeString(conn, fd, field) < 0 || writeString(conn, fd, " ") < 0) + goto cleanup; + + base64_encode_alloc(data, size, &base64); + if (base64 == NULL) { + virReportOOMError(conn); + goto cleanup; + } + if (writeString(conn, fd, base64) < 0 || writeString(conn, fd, "\n") < 0) + goto cleanup; + ret = 0; + + cleanup: + VIR_FREE(base64); + return ret; +} + +static int +writeSecret(virConnectPtr conn, int fd, const virSecretEntry *secret) +{ + const char *s; + + if (writeBase64Data(conn, fd, "id", secret->id, strlen(secret->id)) < 0) + return -1; + + if (secret->ephemeral) + s = "ephemeral yes\n"; + else + s = "ephemeral no\n"; + if (writeString(conn, fd, s) < 0) + return -1; + + if (secret->private) + s = "private yes\n"; + else + s = "private no\n"; + if (writeString(conn, fd, s) < 0) + return -1; + + if (secret->value != NULL && + writeBase64Data(conn, fd, "value", secret->value, + secret->value_size) < 0) + return -1; + if (secret->description != NULL && + writeBase64Data(conn, fd, "description", secret->description, + strlen(secret->description)) < 0) + return -1; + if (secret->volume != NULL && + writeBase64Data(conn, fd, "volume", secret->volume, + strlen(secret->volume)) < 0) + return -1; + + return 0; +} + +static int +saveSecrets(virConnectPtr conn, virSecretDriverStatePtr driver) +{ + const virSecretEntry *secret; + char *tmp_path = NULL; + int fd = -1, ret = -1; + + if (virAsprintf(&tmp_path, "%sXXXXXX", driver->filename) < 0) { + virReportOOMError(conn); + goto cleanup; + } + fd = mkstemp (tmp_path); + if (fd == -1) { + virReportSystemError (conn, errno, _("mkstemp(\"%s\") failed"), + tmp_path); + goto cleanup; + } + + for (secret = driver->secrets; secret != NULL; + secret = secret->next) { + if (!secret->ephemeral && writeSecret(conn, fd, secret) < 0) + goto cleanup; + } + close(fd); + fd = -1; + if (rename(tmp_path, driver->filename) < 0) { + virReportSystemError (conn, errno, _("rename(%s, %s) failed"), tmp_path, + driver->filename); + goto cleanup; + } + VIR_FREE(tmp_path); + ret = 0; + + cleanup: + if (fd != -1) + close(fd); + if (tmp_path != NULL) { + unlink(tmp_path); + VIR_FREE(tmp_path); + } + return ret; +} + +static int +parseBase64String(virConnectPtr conn, const char *base64, char **string) +{ + char *tmp; + size_t size; + + if (!base64_decode_alloc(base64, strlen(base64), &tmp, &size)) { + virSecretReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("invalid format of base64 in secret storage")); + return -1; + } + if (tmp == NULL || VIR_ALLOC_N(*string, size + 1) < 0) { + virReportOOMError(conn); + VIR_FREE(tmp); + return -1; + } + + memcpy(*string, tmp, size); + (*string)[size] = '\0'; + VIR_FREE(tmp); + return 0; +} + +static int +parseKeyValue(virConnectPtr conn, virSecretEntryPtr *list, + virSecretEntryPtr *secret, const char *key, const char *value) +{ + virSecretEntryPtr s; + + s = *secret; + if (s == NULL) { + if (VIR_ALLOC(s) < 0) + goto no_memory; + *secret = s; + } + if (STREQ(key, "id")) { + if (s->id != NULL) { + listInsert(list, s); + if (VIR_ALLOC(s) < 0) + goto no_memory; + *secret = s; + } + if (parseBase64String(conn, value, &s->id) < 0) + return -1; + } else if (STREQ(key, "ephemeral")) { + if (STREQ(value, "yes")) + s->ephemeral = 1; + else if (STREQ(value, "no")) + s->ephemeral = 0; + else + goto invalid; + } else if (STREQ(key, "private")) { + if (STREQ(value, "yes")) + s->private = 1; + else if (STREQ(value, "no")) + s->private = 0; + else + goto invalid; + } else if (STREQ(key, "value")) { + char *raw; + + if (s->value != NULL) + return -1; + if (!base64_decode_alloc(value, strlen(value), &raw, &s->value_size)) + goto invalid; + if (raw == NULL) + goto no_memory; + s->value = (unsigned char *)raw; + } else if (STREQ(key, "description")) { + if (s->description != NULL) + goto invalid; + if (parseBase64String(conn, value, &s->description) < 0) + return -1; + } else if (STREQ(key, "volume")) { + if (s->volume != NULL) + goto invalid; + if (parseBase64String(conn, value, &s->volume) < 0) + return -1; + } else + goto invalid; + + return 0; + + invalid: + virSecretReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("invalid format of secret storage")); + return -1; + + no_memory: + virReportOOMError(conn); + return -1; +} + +static int +loadSecrets(virConnectPtr conn, virSecretDriverStatePtr driver, + virSecretEntryPtr *dest) +{ + int ret = -1, fd = -1; + struct stat st; + char *contents = NULL, *strtok_data = NULL, *strtok_first; + const char *key, *value; + virSecretEntryPtr secret = NULL, list = NULL; + + if (stat(driver->filename, &st) < 0) { + if (errno == ENOENT) + return 0; + virReportSystemError (conn, errno, _("cannot stat '%s'"), + driver->filename); + goto cleanup; + } + if ((size_t)st.st_size != st.st_size || (size_t)(st.st_size + 1) == 0) { + virSecretReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("secrets file does not fit in memory")); + goto cleanup; + } + + fd = open(driver->filename, O_RDONLY); + if (fd == -1) { + virReportSystemError (conn, errno, _("cannot open '%s'"), + driver->filename); + goto cleanup; + } + if (VIR_ALLOC_N(contents, st.st_size + 1) < 0) { + virReportOOMError(conn); + goto cleanup; + } + if (saferead(fd, contents, st.st_size) != st.st_size) { + virReportSystemError (conn, errno, _("cannot read '%s'"), + driver->filename); + goto cleanup; + } + close(fd); + fd = -1; + + strtok_first = contents; + while ((key = strtok_r(strtok_first, " ", &strtok_data)) != NULL) { + strtok_first = NULL; + value = strtok_r(strtok_first, "\n", &strtok_data); + if (value == NULL) { + virSecretReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("invalid format of secret storage")); + goto cleanup; + } + if (parseKeyValue(conn, &list, &secret, key, value) < 0) + goto cleanup; + } + if (secret != NULL) { + if (secret->id == NULL) { + virSecretReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("invalid format of secret storage")); + goto cleanup; + } + listInsert(&list, secret); + } + + /* The secrets were collected into "list" in reverse order. This happens + to reverse the order again, preserving the original order of secrets + in the file. */ + while (list != NULL) { + secret = listUnlink(&list); + listInsert(dest, secret); + } + secret = NULL; + + ret = 0; + goto cleanup; + + + cleanup: + secretFree(secret); + while (list != NULL) { + secret = listUnlink(&list); + secretFree(secret); + } + if (fd != -1) + close(fd); + if (contents != NULL) { + memset(contents, 0, st.st_size); + VIR_FREE(contents); + } + return ret; +} + +static virSecretEntryPtr +secretXMLParseNode(virConnectPtr conn, xmlDocPtr xml, xmlNodePtr root) +{ + xmlXPathContextPtr ctxt = NULL; + virSecretEntryPtr secret = NULL, ret = NULL; + char *prop; + + if (!xmlStrEqual(root->name, BAD_CAST "secret")) { + virSecretReportError(conn, VIR_ERR_XML_ERROR, "%s", + _("incorrect root element")); + goto cleanup; + } + + ctxt = xmlXPathNewContext(xml); + if (ctxt == NULL) { + virReportOOMError(conn); + goto cleanup; + } + ctxt->node = root; + + if (VIR_ALLOC(secret) < 0) { + virReportOOMError(conn); + goto cleanup; + } + + prop = virXPathString(conn, "string(./@ephemeral)", ctxt); + if (prop != NULL && STREQ(prop, "yes")) + secret->ephemeral = 1; + VIR_FREE(prop); + + prop = virXPathString(conn, "string(./@private)", ctxt); + if (prop != NULL && STREQ(prop, "yes")) + secret->private = 1; + VIR_FREE(prop); + + secret->id = virXPathString(conn, "string(./uuid)", ctxt); + secret->description = virXPathString(conn, "string(./description)", ctxt); + secret->volume = virXPathString(conn, "string(./volume)", ctxt); + + ret = secret; + secret = NULL; + + cleanup: + secretFree(secret); + xmlXPathFreeContext(ctxt); + return ret; +} + +/* Called from SAX on parsing errors in the XML. */ +static void +catchXMLError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + + if (ctxt) { + virConnectPtr conn = ctxt->_private; + + if (virGetLastError() == NULL && + ctxt->lastError.level == XML_ERR_FATAL && + ctxt->lastError.message != NULL) { + virSecretReportError(conn, VIR_ERR_XML_DETAIL, _("at line %d: %s"), + ctxt->lastError.line, ctxt->lastError.message); + } + } +} + +static virSecretEntryPtr +secretXMLParseString(virConnectPtr conn, const char *xmlStr) +{ + xmlParserCtxtPtr pctxt; + xmlDocPtr xml = NULL; + xmlNodePtr root; + virSecretEntryPtr ret = NULL; + + pctxt = xmlNewParserCtxt(); + if (pctxt == NULL || pctxt->sax == NULL) + goto cleanup; + pctxt->sax->error = catchXMLError; + pctxt->_private = conn; + + xml = xmlCtxtReadDoc(pctxt, BAD_CAST xmlStr, "secret.xml", NULL, + XML_PARSE_NOENT | XML_PARSE_NONET | + XML_PARSE_NOWARNING); + if (xml == NULL) { + if (conn->err.code == VIR_ERR_NONE) + virSecretReportError(conn, VIR_ERR_XML_ERROR, "%s", + _("failed to parse xml document")); + goto cleanup; + } + + root = xmlDocGetRootElement(xml); + if (root == NULL) { + virSecretReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("missing root element")); + goto cleanup; + } + + ret = secretXMLParseNode(conn, xml, root); + + cleanup: + xmlFreeDoc(xml); + xmlFreeParserCtxt(pctxt); + return ret; +} + +static char * +secretXMLFormat(virConnectPtr conn, const virSecretEntry *secret) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + char *tmp; + + virBufferVSprintf(&buf, "<secret ephemeral='%s' private='%s'>\n", + secret->ephemeral ? "yes" : "no", + secret->private ? "yes" : "no"); + virBufferEscapeString(&buf, " <uuid>%s</uuid>\n", secret->id); + if (secret->description != NULL) + virBufferEscapeString(&buf, " <description>%s</description>\n", + secret->description); + if (secret->volume != NULL) + virBufferEscapeString(&buf, " <volume>%s</volume>\n", secret->volume); + virBufferAddLit(&buf, "</secret>\n"); + + if (virBufferError(&buf)) + goto no_memory; + + return virBufferContentAndReset(&buf); + + no_memory: + virReportOOMError(conn); + tmp = virBufferContentAndReset(&buf); + VIR_FREE(tmp); + return NULL; +} + +static virDrvOpenStatus +secretOpen(virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED) { + if (driverState == NULL) + return VIR_DRV_OPEN_DECLINED; + + conn->secretPrivateData = driverState; + return VIR_DRV_OPEN_SUCCESS; +} + +static int +secretClose(virConnectPtr conn) { + conn->secretPrivateData = NULL; + return 0; +} + +static int +secretNumOfSecrets(virConnectPtr conn) +{ + virSecretDriverStatePtr driver = conn->secretPrivateData; + int i; + virSecretEntryPtr secret; + + secretDriverLock(driver); + + i = 0; + for (secret = driver->secrets; secret != NULL; secret = secret->next) + i++; + + secretDriverUnlock(driver); + return i; +} + +static int +secretListSecrets(virConnectPtr conn, char **uuids, int maxuuids) +{ + virSecretDriverStatePtr driver = conn->secretPrivateData; + int i; + virSecretEntryPtr secret; + + memset(uuids, 0, maxuuids * sizeof(*uuids)); + + secretDriverLock(driver); + + i = 0; + for (secret = driver->secrets; secret != NULL; secret = secret->next) { + if (i == maxuuids) + break; + uuids[i] = strdup(secret->id); + if (uuids[i] == NULL) + goto cleanup; + i++; + } + + secretDriverUnlock(driver); + return i; + + cleanup: + secretDriverUnlock(driver); + + for (i = 0; i < maxuuids; i++) + VIR_FREE(uuids[i]); + + return -1; +} + +static virSecretPtr +secretLookupByUUIDString(virConnectPtr conn, const char *uuid) +{ + virSecretDriverStatePtr driver = conn->secretPrivateData; + virSecretPtr ret = NULL; + virSecretEntryPtr *pptr; + + secretDriverLock(driver); + + pptr = secretFind(driver, uuid); + if (pptr == NULL) { + virSecretReportError(conn, VIR_ERR_NO_SECRET, + _("no secret with matching id '%s'"), uuid); + goto cleanup; + } + + ret = virGetSecret(conn, (*pptr)->id); + +cleanup: + secretDriverUnlock(driver); + return ret; +} + +static char * +secretGenerateUUID(virConnectPtr conn, virSecretDriverStatePtr driver) +{ + char *uuid = NULL; + unsigned attempt; + + if (VIR_ALLOC_N(uuid, VIR_UUID_STRING_BUFLEN) < 0) { + virReportOOMError(conn); + goto error; + } + + for (attempt = 0; attempt < 65536; attempt++) { + unsigned char uuid_data[VIR_UUID_BUFLEN]; + + if (virUUIDGenerate(uuid_data) < 0) { + virSecretReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("unable to generate uuid")); + goto error; + } + virUUIDFormat(uuid_data, uuid); + if (secretFind(driver, uuid) == NULL) + return uuid; + } + virSecretReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("too many conflicts when generating an uuid")); + goto error; + +error: + VIR_FREE(uuid); + return NULL; +} + +static void +shallowCopyAttributes(virSecretEntryPtr dest, const virSecretEntry *src) +{ + dest->id = src->id; + dest->ephemeral = src->ephemeral; + dest->private = src->private; + dest->description = src->description; + dest->volume = src->volume; +} + +static virSecretPtr +secretDefineXML(virConnectPtr conn, const char *xml) +{ + virSecretDriverStatePtr driver = conn->secretPrivateData; + virSecretPtr ret = NULL; + virSecretEntry backup; + virSecretEntryPtr secret, new_attrs; + bool secret_is_new; + + new_attrs = secretXMLParseString(conn, xml); + if (new_attrs == NULL) + return NULL; + + secretDriverLock(driver); + + if (new_attrs->id != NULL) + secret = secretFindOrCreate(conn, driver, new_attrs->id, + &secret_is_new); + else { + new_attrs->id = secretGenerateUUID(conn, driver); + if (new_attrs->id == NULL) + goto cleanup; + secret = secretCreate(conn, driver, new_attrs->id); + secret_is_new = true; + } + if (secret == NULL) + goto cleanup; + + /* Save old values of the attributes */ + shallowCopyAttributes(&backup, secret); + + if (backup.private && !new_attrs->private) { + virSecretReportError(conn, VIR_ERR_OPERATION_DENIED, "%s", + virErrorMsg(VIR_ERR_OPERATION_DENIED, NULL)); + goto cleanup; + } + + shallowCopyAttributes(secret, new_attrs); + if (!new_attrs->ephemeral || !backup.ephemeral) { + if (saveSecrets(conn, driver) < 0) + goto restore_backup; + } + /* Saved succesfully - drop old values */ + VIR_FREE(new_attrs); + VIR_FREE(backup.id); + VIR_FREE(backup.description); + VIR_FREE(backup.volume); + + ret = virGetSecret(conn, secret->id); + goto cleanup; + + restore_backup: + /* Error - restore previous state and free new attributes */ + shallowCopyAttributes(secret, &backup); + if (secret_is_new) { + /* "secret" was added to the head of the list above */ + if (listUnlink(&driverState->secrets) != secret) + /* abort() instead? */ + virSecretReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("list of secrets is inconsistent")); + else + secretFree(secret); + } + + cleanup: + secretFree(new_attrs); + secretDriverUnlock(driver); + + return ret; +} + +static char * +secretGetXMLDesc(virSecretPtr obj) +{ + virSecretDriverStatePtr driver = obj->conn->secretPrivateData; + char *ret = NULL; + virSecretEntryPtr *pptr; + + secretDriverLock(driver); + + pptr = secretFind(driver, obj->uuid); + if (pptr == NULL) { + virSecretReportError(obj->conn, VIR_ERR_NO_SECRET, + _("no secret with matching id '%s'"), obj->uuid); + goto cleanup; + } + + ret = secretXMLFormat(obj->conn, *pptr); + + cleanup: + secretDriverUnlock(driver); + + return ret; +} + +static int +secretSetValue(virSecretPtr obj, const unsigned char *value, + size_t value_size) +{ + virSecretDriverStatePtr driver = obj->conn->secretPrivateData; + int ret = -1; + unsigned char *old_value, *new_value; + size_t old_value_size; + virSecretEntryPtr secret, *pptr; + + if (VIR_ALLOC_N(new_value, value_size) < 0) { + virReportOOMError(obj->conn); + return -1; + } + + secretDriverLock(driver); + + pptr = secretFind(driver, obj->uuid); + if (pptr == NULL) { + virSecretReportError(obj->conn, VIR_ERR_NO_SECRET, + _("no secret with matching id '%s'"), obj->uuid); + goto cleanup; + } + secret = *pptr; + + old_value = secret->value; + old_value_size = secret->value_size; + + memcpy(new_value, value, value_size); + secret->value = new_value; + secret->value_size = value_size; + if (!secret->ephemeral) { + if (saveSecrets(obj->conn, driver) < 0) + goto restore_backup; + } + /* Saved succesfully - drop old value */ + if (old_value != NULL) { + memset(old_value, 0, old_value_size); + VIR_FREE(old_value); + } + new_value = NULL; + + ret = 0; + goto cleanup; + + restore_backup: + /* Error - restore previous state and free new value */ + secret->value = old_value; + secret->value_size = old_value_size; + memset(new_value, 0, value_size); + + cleanup: + secretDriverUnlock(driver); + + VIR_FREE(new_value); + + return ret; +} + +static unsigned char * +secretGetValue(virSecretPtr obj, size_t *value_size, + bool libvirt_internal_call) +{ + virSecretDriverStatePtr driver = obj->conn->secretPrivateData; + unsigned char *ret = NULL; + virSecretEntryPtr *pptr, secret; + + secretDriverLock(driver); + + pptr = secretFind(driver, obj->uuid); + if (pptr == NULL) { + virSecretReportError(obj->conn, VIR_ERR_NO_SECRET, + _("no secret with matching id '%s'"), obj->uuid); + goto cleanup; + } + secret = *pptr; + if (secret->value == NULL) { + virSecretReportError(obj->conn, VIR_ERR_NO_SECRET, + _("secret '%s' does not have a value"), obj->uuid); + goto cleanup; + } + + if (!libvirt_internal_call && secret->private) { + virSecretReportError(obj->conn, VIR_ERR_OPERATION_DENIED, "%s", + _("secret is private")); + goto cleanup; + } + + if (VIR_ALLOC_N(ret, secret->value_size) < 0) { + virReportOOMError(obj->conn); + goto cleanup; + } + memcpy(ret, secret->value, secret->value_size); + *value_size = secret->value_size; + + cleanup: + secretDriverUnlock(driver); + + return ret; +} + +static int +secretUndefine(virSecretPtr obj) +{ + virSecretDriverStatePtr driver = obj->conn->secretPrivateData; + int ret = -1; + virSecretEntryPtr *pptr, secret; + + secretDriverLock(driver); + + pptr = secretFind(driver, obj->uuid); + if (pptr == NULL) { + virSecretReportError(obj->conn, VIR_ERR_NO_SECRET, + _("no secret with matching id '%s'"), obj->uuid); + goto cleanup; + } + + secret = listUnlink(pptr); + if (!secret->ephemeral) { + if (saveSecrets(obj->conn, driver) < 0) + goto restore_backup; + } + secretFree(secret); + + ret = 0; + goto cleanup; + + restore_backup: + /* This may change the order of secrets in the list. We don't care. */ + listInsert(&driver->secrets, secret); + + cleanup: + secretDriverUnlock(driver); + + return ret; +} + +static int +secretDriverCleanup(void) +{ + if (driverState == NULL) + return -1; + + secretDriverLock(driverState); + + while (driverState->secrets != NULL) { + virSecretEntryPtr s; + + s = listUnlink(&driverState->secrets); + secretFree(s); + } + VIR_FREE(driverState->filename); + + secretDriverUnlock(driverState); + virMutexDestroy(&driverState->lock); + VIR_FREE(driverState); + + return 0; +} + +static int +secretDriverStartup(int privileged) +{ + char *base = NULL; + + if (VIR_ALLOC(driverState) < 0) + return -1; + + if (virMutexInit(&driverState->lock) < 0) { + VIR_FREE(driverState); + return -1; + } + secretDriverLock(driverState); + + if (privileged) { + base = strdup(SYSCONF_DIR "/libvirt"); + if (base == NULL) + goto out_of_memory; + } else { + uid_t uid = geteuid(); + char *userdir = virGetUserDirectory(NULL, uid); + + if (!userdir) + goto error; + + if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) { + secretLog("out of memory in virAsprintf"); + VIR_FREE(userdir); + goto out_of_memory; + } + VIR_FREE(userdir); + } + if (virAsprintf(&driverState->filename, "%s/secrets", base) == -1) + goto out_of_memory; + VIR_FREE(base); + + if (loadSecrets(NULL, driverState, &driverState->secrets) < 0) + goto error; + + secretDriverUnlock(driverState); + return 0; + + out_of_memory: + secretLog("virSecretStartup: out of memory"); + error: + VIR_FREE(base); + secretDriverUnlock(driverState); + secretDriverCleanup(); + return -1; +} + +static int +secretDriverReload(void) +{ + virSecretEntryPtr new_secrets = NULL; + + if (!driverState) + return -1; + + secretDriverLock(driverState); + + if (loadSecrets(NULL, driverState, &new_secrets) < 0) + goto end; + + /* Keep ephemeral secrets from current state. Discard non-ephemeral secrets + that were removed by the secrets file. */ + while (driverState->secrets != NULL) { + virSecretEntryPtr s; + + s = listUnlink(&driverState->secrets); + if (s->ephemeral) + listInsert(&new_secrets, s); + else + secretFree(s); + } + driverState->secrets = new_secrets; + + end: + secretDriverUnlock(driverState); + return 0; +} + +static virSecretDriver secretDriver = { + .name = "secret", + .open = secretOpen, + .close = secretClose, + .numOfSecrets = secretNumOfSecrets, + .listSecrets = secretListSecrets, + .lookupByUUIDString = secretLookupByUUIDString, + .defineXML = secretDefineXML, + .getXMLDesc = secretGetXMLDesc, + .setValue = secretSetValue, + .getValue = secretGetValue, + .undefine = secretUndefine +}; + +static virStateDriver stateDriver = { + .initialize = secretDriverStartup, + .cleanup = secretDriverCleanup, + .reload = secretDriverReload, + .active = NULL /* All persistent state is immediately saved to disk */ +}; + +int +secretRegister(void) +{ + virRegisterSecretDriver(&secretDriver); + virRegisterStateDriver(&stateDriver); + return 0; +} diff --git a/src/secret_driver.h b/src/secret_driver.h new file mode 100644 index 0000000..0d0b80a --- /dev/null +++ b/src/secret_driver.h @@ -0,0 +1,28 @@ +/* + * secret_driver.h: local driver for secret manipulation API + * + * Copyright (C) 2009 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Red Hat Author: Miloslav Trmač <mitr@redhat.com> + */ + +#ifndef __VIR_SECRET_DRIVER_H__ +#define __VIR_SECRET_DRIVER_H__ + +int secretRegister(void); + +#endif /* __VIR_SECRET_DRIVER_H__ */ diff --git a/src/test.c b/src/test.c index 305f2c9..7c8f85b 100644 --- a/src/test.c +++ b/src/test.c @@ -4173,6 +4173,20 @@ static void testDomainEventQueue(testConnPtr driver, virEventUpdateTimeout(driver->domainEventTimer, 0); } +static virDrvOpenStatus testSecretOpen(virConnectPtr conn, + virConnectAuthPtr auth ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED) { + if (STRNEQ(conn->driver->name, "Test")) + return VIR_DRV_OPEN_DECLINED; + + conn->secretPrivateData = conn->privateData; + return VIR_DRV_OPEN_SUCCESS; +} + +static int testSecretClose(virConnectPtr conn) { + conn->secretPrivateData = NULL; + return 0; +} static virDriver testDriver = { VIR_DRV_TEST, @@ -4328,6 +4342,11 @@ static virDeviceMonitor testDevMonitor = { .close = testDevMonClose, }; +static virSecretDriver testSecretDriver = { + .name = "Test", + .open = testSecretOpen, + .close = testSecretClose, +}; /** @@ -4348,6 +4367,8 @@ testRegister(void) return -1; if (virRegisterDeviceMonitor(&testDevMonitor) < 0) return -1; + if (virRegisterSecretDriver(&testSecretDriver) < 0) + return -1; return 0; } diff --git a/src/virterror.c b/src/virterror.c index 2a3cdaf..77b295c 100644 --- a/src/virterror.c +++ b/src/virterror.c @@ -1082,6 +1082,11 @@ virErrorMsg(virErrorNumber error, const char *info) errmsg = _("Invalid secret"); else errmsg = _("Invalid secret: %s"); + case VIR_ERR_NO_SECRET: + if (info == NULL) + errmsg = _("Secret not found"); + else + errmsg = _("Secret not found: %s"); break; } return (errmsg); -- 1.6.2.5

On Sun, Aug 16, 2009 at 10:48:00PM +0200, Miloslav Trmač wrote:
This implementation stores the secrets in an unencrypted text file, for simplicity in implementation and debugging.
(Symmetric encryption, e.g. using gpgme, will not be difficult to add. Because the TLS private key used by libvirtd is stored unencrypted, encrypting the secrets file does not currently provide much additional security.)
What if we change our mind in some time, would there be any obstacle to dynamically detecting things are not encrypted and switching to a crypted file transparently? I'm just trying to make sure a decision taken now won't become a obstacle on deployed instances if we ever revisit the issue. [...]
diff --git a/src/secret_driver.c b/src/secret_driver.c new file mode 100644 index 0000000..d9e638c --- /dev/null +++ b/src/secret_driver.c @@ -0,0 +1,1102 @@ [...] +#define virSecretReportError(conn, code, fmt...) \ + virReportErrorHelper(conn, VIR_FROM_SECRET, code, __FILE__, \ + __FUNCTION__, __LINE__, fmt) + +#define secretLog(msg...) fprintf(stderr, msg)
argh, no please let's use the existing log mechanism and not push more fprintf based debugging #include "logging.h" and #define secretLog(level, msg, ...) \ virLogMessage(__FILE__, level, 0, msg, __VA_ARGS__) and use one of the virLogPriority values for level
+typedef struct _virSecretEntry virSecretEntry; +typedef virSecretEntry *virSecretEntryPtr; +struct _virSecretEntry { + virSecretEntryPtr next; + char *id; /* We generate UUIDs, but don't restrict user-chosen IDs */ + unsigned char *value; /* May be NULL */ + size_t value_size; + unsigned ephemeral : 1; + unsigned private : 1; + char *description, *volume; /* May be NULL */
for structs I prefer one entry per line char *description; char *volume;
+};
cosmetic but in line with other code [...]
+static virSecretEntryPtr * +secretFind(virSecretDriverStatePtr driver, const char *uuid) +{ + virSecretEntryPtr *pptr, s; + + for (pptr = &driver->secrets; (s = *pptr) != NULL; pptr = &s->next) {
Urgh, a test with an affectation side effect in the loop guard, please clean this up, this is really hard to figure out
+ if (STREQ(s->id, uuid)) + return pptr; + } + return NULL; +} + +static int +writeBase64Data(virConnectPtr conn, int fd, const char *field, + const void *data, size_t size) +{ + int ret = -1; + char *base64 = NULL; + + if (writeString(conn, fd, field) < 0 || writeString(conn, fd, " ") < 0) + goto cleanup; + + base64_encode_alloc(data, size, &base64);
where is base64_encode_alloc coming from ? [...]
+static int +saveSecrets(virConnectPtr conn, virSecretDriverStatePtr driver) +{ + const virSecretEntry *secret; + char *tmp_path = NULL; + int fd = -1, ret = -1; + + if (virAsprintf(&tmp_path, "%sXXXXXX", driver->filename) < 0) { + virReportOOMError(conn); + goto cleanup; + } + fd = mkstemp (tmp_path);
Hum even if unencrypted, we should make sure of the mode of the file beforehand... isn't there a safer equivalent (possibly made postable by gnulib ?)
+ if (fd == -1) { + virReportSystemError (conn, errno, _("mkstemp(\"%s\") failed"), + tmp_path); + goto cleanup; + } + + for (secret = driver->secrets; secret != NULL; + secret = secret->next) { + if (!secret->ephemeral && writeSecret(conn, fd, secret) < 0) + goto cleanup; + } + close(fd); + fd = -1; + if (rename(tmp_path, driver->filename) < 0) { + virReportSystemError (conn, errno, _("rename(%s, %s) failed"), tmp_path, + driver->filename); + goto cleanup; + }
Hum, the whole set smells fishy, we are creating a temp file, without mode checked, then moving that file somewhere else. I would ratehr have internal APIsdeling with a dump to memory and then a single open, safe and directly to the driver->filename.
+static int +parseBase64String(virConnectPtr conn, const char *base64, char **string) +{ + char *tmp; + size_t size; + + if (!base64_decode_alloc(base64, strlen(base64), &tmp, &size)) {
where is base64_decode_alloc coming from ?
+ virSecretReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("invalid format of base64 in secret storage")); + return -1; + } + if (tmp == NULL || VIR_ALLOC_N(*string, size + 1) < 0) { + virReportOOMError(conn); + VIR_FREE(tmp); + return -1; + } + + memcpy(*string, tmp, size); + (*string)[size] = '\0'; + VIR_FREE(tmp); + return 0; +}
+static int +parseKeyValue(virConnectPtr conn, virSecretEntryPtr *list, + virSecretEntryPtr *secret, const char *key, const char *value) +{ + virSecretEntryPtr s; + + s = *secret; + if (s == NULL) { + if (VIR_ALLOC(s) < 0) + goto no_memory; + *secret = s; + } + if (STREQ(key, "id")) { + if (s->id != NULL) { + listInsert(list, s); + if (VIR_ALLOC(s) < 0) + goto no_memory; + *secret = s; + } + if (parseBase64String(conn, value, &s->id) < 0) + return -1; + } else if (STREQ(key, "ephemeral")) { + if (STREQ(value, "yes")) + s->ephemeral = 1; + else if (STREQ(value, "no")) + s->ephemeral = 0; + else + goto invalid;
here
+ } else if (STREQ(key, "private")) { + if (STREQ(value, "yes")) + s->private = 1; + else if (STREQ(value, "no")) + s->private = 0; + else + goto invalid;
and here, it's better to state why parsing failed rather than just let the user guess. We have the info let's give it back
+ } else if (STREQ(key, "value")) {
+static int +loadSecrets(virConnectPtr conn, virSecretDriverStatePtr driver, + virSecretEntryPtr *dest) +{ + int ret = -1, fd = -1; + struct stat st; + char *contents = NULL, *strtok_data = NULL, *strtok_first; + const char *key, *value; + virSecretEntryPtr secret = NULL, list = NULL; + + if (stat(driver->filename, &st) < 0) { + if (errno == ENOENT) + return 0; + virReportSystemError (conn, errno, _("cannot stat '%s'"), + driver->filename); + goto cleanup; + } + if ((size_t)st.st_size != st.st_size || (size_t)(st.st_size + 1) == 0) { + virSecretReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("secrets file does not fit in memory")); + goto cleanup; + } + + fd = open(driver->filename, O_RDONLY); + if (fd == -1) { + virReportSystemError (conn, errno, _("cannot open '%s'"), + driver->filename); + goto cleanup; + }
stat()/open() introduces a small race, I think open() and then fdstat() is a bit cleaner, not a big deal though
+ if (VIR_ALLOC_N(contents, st.st_size + 1) < 0) { + virReportOOMError(conn); + goto cleanup; + } + if (saferead(fd, contents, st.st_size) != st.st_size) { + virReportSystemError (conn, errno, _("cannot read '%s'"), + driver->filename); + goto cleanup; + } + close(fd); + fd = -1;
contents[st.st_size] = 0; needed here.
+ strtok_first = contents; [...] +static virSecretEntryPtr +secretXMLParseNode(virConnectPtr conn, xmlDocPtr xml, xmlNodePtr root) +{ + xmlXPathContextPtr ctxt = NULL; + virSecretEntryPtr secret = NULL, ret = NULL; + char *prop; + + if (!xmlStrEqual(root->name, BAD_CAST "secret")) { + virSecretReportError(conn, VIR_ERR_XML_ERROR, "%s", + _("incorrect root element")); + goto cleanup; + } + + ctxt = xmlXPathNewContext(xml); + if (ctxt == NULL) { + virReportOOMError(conn); + goto cleanup; + } + ctxt->node = root; + + if (VIR_ALLOC(secret) < 0) { + virReportOOMError(conn); + goto cleanup; + } + + prop = virXPathString(conn, "string(./@ephemeral)", ctxt); + if (prop != NULL && STREQ(prop, "yes")) + secret->ephemeral = 1;
we should test for "no" and explicitely fail otherwise if (prop != NULL) { if (STREQ(prop, "yes")) { secret->ephemeral = 1; } else if (STREQ(prop, "no")) { secret->ephemeral = 0; } else { raise an error } VIR_FREE(prop); }
+ VIR_FREE(prop); + + prop = virXPathString(conn, "string(./@private)", ctxt); + if (prop != NULL && STREQ(prop, "yes")) + secret->private = 1; + VIR_FREE(prop);
same here
+ secret->id = virXPathString(conn, "string(./uuid)", ctxt); + secret->description = virXPathString(conn, "string(./description)", ctxt); + secret->volume = virXPathString(conn, "string(./volume)", ctxt); + + ret = secret; + secret = NULL; + + cleanup: + secretFree(secret); + xmlXPathFreeContext(ctxt); + return ret; +} [...] [...] + restore_backup: + /* Error - restore previous state and free new attributes */ + shallowCopyAttributes(secret, &backup); + if (secret_is_new) { + /* "secret" was added to the head of the list above */ + if (listUnlink(&driverState->secrets) != secret) + /* abort() instead? */
no we can't abort() in the library
+ virSecretReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("list of secrets is inconsistent")); + else + secretFree(secret); + } + + cleanup: + secretFree(new_attrs); + secretDriverUnlock(driver); + + return ret; +}
+static int +secretSetValue(virSecretPtr obj, const unsigned char *value, + size_t value_size) +{ + virSecretDriverStatePtr driver = obj->conn->secretPrivateData; + int ret = -1; + unsigned char *old_value, *new_value; + size_t old_value_size; + virSecretEntryPtr secret, *pptr; + + if (VIR_ALLOC_N(new_value, value_size) < 0) { + virReportOOMError(obj->conn); + return -1; + } + + secretDriverLock(driver); + + pptr = secretFind(driver, obj->uuid); + if (pptr == NULL) { + virSecretReportError(obj->conn, VIR_ERR_NO_SECRET, + _("no secret with matching id '%s'"), obj->uuid); + goto cleanup; + }
I would be tempted to add an immutable flag to a secret, basically this would allow to set the value once but forbid ever changing it we would just test here that secret->value is NULL before allowing to set it if immutable. But it's easy to add later if needed.
+ secret = *pptr; + + old_value = secret->value; + old_value_size = secret->value_size; +
So there is a few points to check IMHO, also I would like to understand where the base64 encoding/decoding routines come from, actually I would prefer to have them in utils.[ch] and with function names matching the existing conventions. Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Changes since the second submission: - Change some command names to better follow the conventions - Update for the changed public API - Print (potentially auto-generated) secret UUID on successful secret-define - s/secret_id/uuid/g - use "unsigned char *" for secret value --- src/virsh.c | 323 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 323 insertions(+), 0 deletions(-) diff --git a/src/virsh.c b/src/virsh.c index 94c3c4e..2d98e33 100644 --- a/src/virsh.c +++ b/src/virsh.c @@ -41,6 +41,7 @@ #endif #include "internal.h" +#include "base64.h" #include "buf.h" #include "console.h" #include "util.h" @@ -271,6 +272,9 @@ static virStorageVolPtr vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd, vshCommandOptVolBy(_ctl, _cmd, _optname, _pooloptname, _name, \ VSH_BYUUID|VSH_BYNAME) +static virSecretPtr vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, + char **name); + static void vshPrintExtra(vshControl *ctl, const char *format, ...) ATTRIBUTE_FMT_PRINTF(2, 3); static void vshDebug(vshControl *ctl, int level, const char *format, ...) @@ -5249,9 +5253,291 @@ cmdVolPath(vshControl *ctl, const vshCmd *cmd) } +/* + * "secret-define" command + */ +static const vshCmdInfo info_secret_define[] = { + {"help", gettext_noop("define or modify a secret from an XML file")}, + {"desc", gettext_noop("Define or modify a secret.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_secret_define[] = { + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("file containing secret attributes in XML")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdSecretDefine(vshControl *ctl, const vshCmd *cmd) +{ + char *from, *buffer, *uuid; + virSecretPtr res; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + from = vshCommandOptString(cmd, "file", NULL); + if (!from) + return FALSE; + + if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) + return FALSE; + + res = virSecretDefineXML(ctl->conn, buffer); + free (buffer); + + if (res == NULL) { + vshError(ctl, FALSE, _("Failed to set attributes from %s"), from); + return FALSE; + } + uuid = virSecretGetUUIDString(res); + if (uuid == NULL) { + vshError(ctl, FALSE, "%s", + _("Failed to get UUID of created secret")); + virSecretFree(res); + return FALSE; + } + vshPrint(ctl, _("Secret %s created\n"), uuid); + free(uuid); + virSecretFree(res); + return TRUE; +} + +/* + * "secret-dumpxml" command + */ +static const vshCmdInfo info_secret_dumpxml[] = { + {"help", gettext_noop("secret attributes in XML")}, + {"desc", gettext_noop("Output attributes of a secret as an XML dump to stdout.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_secret_dumpxml[] = { + {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("secret UUID")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdSecretDumpXML(vshControl *ctl, const vshCmd *cmd) +{ + virSecretPtr secret; + int ret = FALSE; + char *xml; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + secret = vshCommandOptSecret(ctl, cmd, NULL); + if (secret == NULL) + return FALSE; + + xml = virSecretGetXMLDesc(secret); + if (xml == NULL) + goto cleanup; + printf("%s", xml); + free(xml); + ret = TRUE; + +cleanup: + virSecretFree(secret); + return ret; +} + +/* + * "secret-set-value" command + */ +static const vshCmdInfo info_secret_set_value[] = { + {"help", gettext_noop("set a secret value")}, + {"desc", gettext_noop("Set a secret value.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_secret_set_value[] = { + {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("secret UUID")}, + {"base64", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("base64-encoded secret value")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdSecretSetValue(vshControl *ctl, const vshCmd *cmd) +{ + virSecretPtr secret; + size_t value_size; + char *base64, *value; + int found, res, ret = FALSE; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + secret = vshCommandOptSecret(ctl, cmd, NULL); + if (secret == NULL) + return FALSE; + + base64 = vshCommandOptString(cmd, "base64", &found); + if (!base64) + goto cleanup; + + if (!base64_decode_alloc(base64, strlen(base64), &value, &value_size)) { + vshError(ctl, FALSE, _("Invalid base64 data")); + goto cleanup; + } + if (value == NULL) { + vshError(ctl, FALSE, "%s", _("Failed to allocate memory")); + return FALSE; + } + + res = virSecretSetValue(secret, (unsigned char *)value, value_size); + memset(value, 0, value_size); + free (value); + + if (res != 0) { + vshError(ctl, FALSE, "%s", _("Failed to set secret value")); + goto cleanup; + } + vshPrint(ctl, "%s", _("Secret value set\n")); + ret = TRUE; + +cleanup: + virSecretFree(secret); + return ret; +} + +/* + * "secret-get-value" command + */ +static const vshCmdInfo info_secret_get_value[] = { + {"help", gettext_noop("Output a secret value")}, + {"desc", gettext_noop("Output a secret value to stdout.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_secret_get_value[] = { + {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("secret UUID")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdSecretGetValue(vshControl *ctl, const vshCmd *cmd) +{ + virSecretPtr secret; + char *base64; + unsigned char *value; + size_t value_size; + int ret = FALSE; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + secret = vshCommandOptSecret(ctl, cmd, NULL); + if (secret == NULL) + return FALSE; + + value = virSecretGetValue(secret, &value_size); + if (value == NULL) + goto cleanup; + + base64_encode_alloc((char *)value, value_size, &base64); + memset(value, 0, value_size); + free(value); + + if (base64 == NULL) { + vshError(ctl, FALSE, "%s", _("Failed to allocate memory")); + goto cleanup; + } + printf("%s", base64); + memset(base64, 0, strlen(base64)); + free(base64); + ret = TRUE; + +cleanup: + virSecretFree(secret); + return ret; +} + +/* + * "secret-undefine" command + */ +static const vshCmdInfo info_secret_undefine[] = { + {"help", gettext_noop("undefine a secret")}, + {"desc", gettext_noop("Undefine a secret.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_secret_undefine[] = { + {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("secret UUID")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdSecretUndefine(vshControl *ctl, const vshCmd *cmd) +{ + virSecretPtr secret; + int ret = FALSE; + char *uuid; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + secret = vshCommandOptSecret(ctl, cmd, &uuid); + if (secret == NULL) + return FALSE; + + if (virSecretUndefine(secret) < 0) { + vshError(ctl, FALSE, _("Failed to delete secret %s"), uuid); + goto cleanup; + } + vshPrint(ctl, _("Secret %s deleted\n"), uuid); + ret = TRUE; + +cleanup: + virSecretFree(secret); + return ret; +} + +/* + * "secret-list" command + */ +static const vshCmdInfo info_secret_list[] = { + {"help", gettext_noop("list secrets")}, + {"desc", gettext_noop("Returns a list of secrets")}, + {NULL, NULL} +}; + +static int +cmdSecretList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + int maxuuids = 0, i; + char **uuids = NULL; + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + maxuuids = virConnectNumOfSecrets(ctl->conn); + if (maxuuids < 0) { + vshError(ctl, FALSE, "%s", _("Failed to list secrets")); + return FALSE; + } + uuids = vshMalloc(ctl, sizeof(*uuids) * maxuuids); + maxuuids = virConnectListSecrets(ctl->conn, uuids, maxuuids); + if (maxuuids < 0) { + vshError(ctl, FALSE, "%s", _("Failed to list secrets")); + free(uuids); + return FALSE; + } + + qsort(uuids, maxuuids, sizeof(char *), namesorter); + + vshPrintExtra(ctl, "%s\n", _("UUID")); + vshPrintExtra(ctl, "-----------------------------------------\n"); + + for (i = 0; i < maxuuids; i++) { + vshPrint(ctl, "%-36s\n", uuids[i]); + free(uuids[i]); + } + free(uuids); + return TRUE; +} /* @@ -6921,6 +7207,14 @@ static const vshCmdDef commands[] = { {"pool-undefine", cmdPoolUndefine, opts_pool_undefine, info_pool_undefine}, {"pool-uuid", cmdPoolUuid, opts_pool_uuid, info_pool_uuid}, + {"secret-define", cmdSecretDefine, opts_secret_define, info_secret_define}, + {"secret-dumpxml", cmdSecretDumpXML, opts_secret_dumpxml, info_secret_dumpxml}, + {"secret-set-value", cmdSecretSetValue, opts_secret_set_value, info_secret_set_value}, + {"secret-get-value", cmdSecretGetValue, opts_secret_get_value, info_secret_get_value}, + {"secret-undefine", cmdSecretUndefine, opts_secret_undefine, info_secret_undefine}, + {"secret-list", cmdSecretList, NULL, info_secret_list}, + + #ifndef WIN32 {"pwd", cmdPwd, NULL, info_pwd}, #endif @@ -7480,6 +7774,35 @@ vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd, return vol; } +static virSecretPtr +vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, char **name) +{ + virSecretPtr secret = NULL; + char *n; + const char *optname = "secret"; + + if (!cmd_has_option (ctl, cmd, optname)) + return NULL; + + n = vshCommandOptString(cmd, optname, NULL); + if (n == NULL) { + vshError(ctl, FALSE, "%s", _("undefined secret UUID")); + return NULL; + } + + vshDebug(ctl, 5, "%s: found option <%s>: %s\n", cmd->def->name, optname, n); + + if (name != NULL) + *name = n; + + secret = virSecretLookupByUUIDString(ctl->conn, n); + + if (secret == NULL) + vshError(ctl, FALSE, _("failed to get secret '%s'"), n); + + return secret; +} + /* * Executes command(s) and returns return code from last command */ -- 1.6.2.5

On Sun, Aug 16, 2009 at 10:48:01PM +0200, Miloslav Trmač wrote:
Changes since the second submission: - Change some command names to better follow the conventions - Update for the changed public API - Print (potentially auto-generated) secret UUID on successful secret-define - s/secret_id/uuid/g - use "unsigned char *" for secret value --- src/virsh.c | 323 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 323 insertions(+), 0 deletions(-)
ACK, I assume the man page is updated in another patch :-) Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

This commit represents results of (make -C docs api) - if this patch does not apply, just re-run the command. The API data gathered by this commit is necessary to make step 10 (Python bindings) usable. --- docs/devhelp/libvirt-libvirt.html | 86 ++++++++- docs/devhelp/libvirt-virterror.html | 8 +- docs/html/libvirt-libvirt.html | 35 ++++- docs/html/libvirt-virterror.html | 4 +- docs/libvirt-api.xml | 115 ++++++++++-- docs/libvirt-refs.xml | 352 ++++++++++++++++++++++++++--------- 6 files changed, 486 insertions(+), 114 deletions(-) diff --git a/docs/devhelp/libvirt-libvirt.html b/docs/devhelp/libvirt-libvirt.html index 0ac96d5..40cd991 100644 --- a/docs/devhelp/libvirt-libvirt.html +++ b/docs/devhelp/libvirt-libvirt.html @@ -59,6 +59,7 @@ typedef struct _virNetwork <a href="#virNetwork">virNetwork</a>; typedef enum <a href="#virDomainEventResumedDetailType">virDomainEventResumedDetailType</a>; typedef <a href="libvirt-libvirt.html#virDomainBlockStatsStruct">virDomainBlockStatsStruct</a> * <a href="#virDomainBlockStatsPtr">virDomainBlockStatsPtr</a>; typedef struct _virConnect <a href="#virConnect">virConnect</a>; +typedef <a href="libvirt-libvirt.html#virSecret">virSecret</a> * <a href="#virSecretPtr">virSecretPtr</a>; typedef enum <a href="#virDomainEventStartedDetailType">virDomainEventStartedDetailType</a>; typedef struct _virDomainInfo <a href="#virDomainInfo">virDomainInfo</a>; typedef enum <a href="#virStoragePoolDeleteFlags">virStoragePoolDeleteFlags</a>; @@ -67,6 +68,7 @@ typedef struct _virStoragePool <a href="#virStoragePool">virStoragePool</a>; typedef enum <a href="#virDomainEventType">virDomainEventType</a>; typedef struct _virDomainInterfaceStats <a href="#virDomainInterfaceStatsStruct">virDomainInterfaceStatsStruct</a>; typedef struct _virStoragePoolInfo <a href="#virStoragePoolInfo">virStoragePoolInfo</a>; +typedef struct _virSecret <a href="#virSecret">virSecret</a>; typedef enum <a href="#virDomainState">virDomainState</a>; typedef struct _virDomain <a href="#virDomain">virDomain</a>; typedef <a href="libvirt-libvirt.html#virDomainInterfaceStatsStruct">virDomainInterfaceStatsStruct</a> * <a href="#virDomainInterfaceStatsPtr">virDomainInterfaceStatsPtr</a>; @@ -113,16 +115,18 @@ typedef enum <a href="#virDomainCreateFlags">virDomainCreateFlags</a>; typedef <a href="libvirt-libvirt.html#virSecurityLabel">virSecurityLabel</a> * <a href="#virSecurityLabelPtr">virSecurityLabelPtr</a>; typedef struct _virSecurityModel <a href="#virSecurityModel">virSecurityModel</a>; char * <a href="#virStoragePoolGetXMLDesc">virStoragePoolGetXMLDesc</a> (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br/> unsigned int flags); +char * <a href="#virSecretGetUUIDString">virSecretGetUUIDString</a> (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret); const char * <a href="#virStorageVolGetKey">virStorageVolGetKey</a> (<a href="libvirt-libvirt.html#virStorageVolPtr">virStorageVolPtr</a> vol); typedef void <a href="#virEventUpdateTimeoutFunc">virEventUpdateTimeoutFunc</a> (int timer, <br/> int timeout); -int <a href="#virConnectClose">virConnectClose</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn); +int <a href="#virDomainUndefine">virDomainUndefine</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain); <a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> <a href="#virDomainDefineXML">virDomainDefineXML</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * xml); int <a href="#virDomainShutdown">virDomainShutdown</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain); -int <a href="#virConnectListStoragePools">virConnectListStoragePools</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> char ** const names, <br/> int maxnames); +int <a href="#virConnectListDefinedInterfaces">virConnectListDefinedInterfaces</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> char ** const names, <br/> int maxnames); int <a href="#virGetVersion">virGetVersion</a> (unsigned long * libVer, <br/> const char * type, <br/> unsigned long * typeVer); int <a href="#virNodeGetCellsFreeMemory">virNodeGetCellsFreeMemory</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> unsigned long long * freeMems, <br/> int startCell, <br/> int maxCells); int <a href="#virInitialize">virInitialize</a> (void); const char * <a href="#virNodeDeviceGetName">virNodeDeviceGetName</a> (<a href="libvirt-libvirt.html#virNodeDevicePtr">virNodeDevicePtr</a> dev); +int <a href="#virConnectNumOfSecrets">virConnectNumOfSecrets</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn); int <a href="#virStoragePoolSetAutostart">virStoragePoolSetAutostart</a> (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br/> int autostart); char * <a href="#virConnectDomainXMLFromNative">virConnectDomainXMLFromNative</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * nativeFormat, <br/> const char * nativeConfig, <br/> unsigned int flags); int <a href="#virNodeDeviceDettach">virNodeDeviceDettach</a> (<a href="libvirt-libvirt.html#virNodeDevicePtr">virNodeDevicePtr</a> dev); @@ -131,7 +135,7 @@ int <a href="#virConnectDomainEventDeregister">virConnectDomainEventDeregister</ int <a href="#virDomainGetSchedulerParameters">virDomainGetSchedulerParameters</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain, <br/> <a href="libvirt-libvirt.html#virSchedParameterPtr">virSchedParameterPtr</a> params, <br/> int * nparams); <a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> <a href="#virDomainLookupByUUIDString">virDomainLookupByUUIDString</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * uuidstr); int <a href="#virConnectNumOfDefinedNetworks">virConnectNumOfDefinedNetworks</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn); -int <a href="#virConnectListDefinedInterfaces">virConnectListDefinedInterfaces</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> char ** const names, <br/> int maxnames); +int <a href="#virConnectListStoragePools">virConnectListStoragePools</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> char ** const names, <br/> int maxnames); int <a href="#virNetworkGetUUID">virNetworkGetUUID</a> (<a href="libvirt-libvirt.html#virNetworkPtr">virNetworkPtr</a> network, <br/> unsigned char * uuid); char * <a href="#virInterfaceGetXMLDesc">virInterfaceGetXMLDesc</a> (<a href="libvirt-libvirt.html#virInterfacePtr">virInterfacePtr</a> iface, <br/> unsigned int flags); <a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> <a href="#virStoragePoolGetConnect">virStoragePoolGetConnect</a> (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool); @@ -155,6 +159,7 @@ typedef void <a href="#virEventUpdateHandleFunc">virEventUpdateHandleFunc</a> (i int <a href="#virDomainDestroy">virDomainDestroy</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain); int <a href="#virConnectNumOfNetworks">virConnectNumOfNetworks</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn); <a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> <a href="#virStoragePoolLookupByUUIDString">virStoragePoolLookupByUUIDString</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * uuidstr); +<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> <a href="#virSecretGetConnect">virSecretGetConnect</a> (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret); int <a href="#virInterfaceCreate">virInterfaceCreate</a> (<a href="libvirt-libvirt.html#virInterfacePtr">virInterfacePtr</a> iface, <br/> unsigned int flags); char * <a href="#virDomainGetXMLDesc">virDomainGetXMLDesc</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain, <br/> int flags); int <a href="#virStoragePoolGetUUID">virStoragePoolGetUUID</a> (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br/> unsigned char * uuid); @@ -181,6 +186,7 @@ const char * <a href="#virInterfaceGetName">virInterfaceGetName</a> (<a href="li int <a href="#virStoragePoolCreate">virStoragePoolCreate</a> (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br/> unsigned int flags); int <a href="#virNodeGetInfo">virNodeGetInfo</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> <a href="libvirt-libvirt.html#virNodeInfoPtr">virNodeInfoPtr</a> info); int <a href="#virNetworkSetAutostart">virNetworkSetAutostart</a> (<a href="libvirt-libvirt.html#virNetworkPtr">virNetworkPtr</a> network, <br/> int autostart); +<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> <a href="#virSecretLookupByUUIDString">virSecretLookupByUUIDString</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * uuid); unsigned long <a href="#virDomainGetMaxMemory">virDomainGetMaxMemory</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain); int <a href="#virStoragePoolFree">virStoragePoolFree</a> (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool); int <a href="#virConnectNumOfDefinedInterfaces">virConnectNumOfDefinedInterfaces</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn); @@ -190,7 +196,7 @@ int <a href="#virNodeDeviceListCaps">virNodeDeviceListCaps</a> (<a href="libvir int <a href="#virDomainBlockStats">virDomainBlockStats</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> dom, <br/> const char * path, <br/> <a href="libvirt-libvirt.html#virDomainBlockStatsPtr">virDomainBlockStatsPtr</a> stats, <br/> size_t size); <a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> <a href="#virConnectOpenAuth">virConnectOpenAuth</a> (const char * name, <br/> <a href="libvirt-libvirt.html#virConnectAuthPtr">virConnectAuthPtr</a> auth, <br/> int flags); int <a href="#virStoragePoolDelete">virStoragePoolDelete</a> (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br/> unsigned int flags); -typedef int <a href="#virEventRemoveHandleFunc">virEventRemoveHandleFunc</a> (int watch); +int <a href="#virDomainResume">virDomainResume</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain); const char * <a href="#virStorageVolGetName">virStorageVolGetName</a> (<a href="libvirt-libvirt.html#virStorageVolPtr">virStorageVolPtr</a> vol); int <a href="#virStoragePoolGetAutostart">virStoragePoolGetAutostart</a> (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br/> int * autostart); int <a href="#virDomainGetAutostart">virDomainGetAutostart</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain, <br/> int * autostart); @@ -203,10 +209,12 @@ char * <a href="#virNetworkGetXMLDesc">virNetworkGetXMLDesc</a> (<a href="libvi int <a href="#virConnectNumOfStoragePools">virConnectNumOfStoragePools</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn); <a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> <a href="#virInterfaceGetConnect">virInterfaceGetConnect</a> (<a href="libvirt-libvirt.html#virInterfacePtr">virInterfacePtr</a> iface); const char * <a href="#virNetworkGetName">virNetworkGetName</a> (<a href="libvirt-libvirt.html#virNetworkPtr">virNetworkPtr</a> network); +char * <a href="#virSecretGetXMLDesc">virSecretGetXMLDesc</a> (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret); int <a href="#virConnectListDefinedDomains">virConnectListDefinedDomains</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> char ** const names, <br/> int maxnames); char * <a href="#virConnectGetCapabilities">virConnectGetCapabilities</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn); <a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> <a href="#virDomainLookupByName">virDomainLookupByName</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * name); char * <a href="#virConnectFindStoragePoolSources">virConnectFindStoragePoolSources</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * type, <br/> const char * srcSpec, <br/> unsigned int flags); +int <a href="#virStorageVolFree">virStorageVolFree</a> (<a href="libvirt-libvirt.html#virStorageVolPtr">virStorageVolPtr</a> vol); int <a href="#virDomainPinVcpu">virDomainPinVcpu</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain, <br/> unsigned int vcpu, <br/> unsigned char * cpumap, <br/> int maplen); int <a href="#virNodeGetSecurityModel">virNodeGetSecurityModel</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> <a href="libvirt-libvirt.html#virSecurityModelPtr">virSecurityModelPtr</a> secmodel); int <a href="#virDomainRestore">virDomainRestore</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * from); @@ -216,7 +224,7 @@ char * <a href="#virStorageVolGetPath">virStorageVolGetPath</a> (<a href="libvi typedef int <a href="#virConnectDomainEventCallback">virConnectDomainEventCallback</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> <a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> dom, <br/> int event, <br/> int detail, <br/> void * opaque); <a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> <a href="#virDomainLookupByID">virDomainLookupByID</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> int id); int <a href="#virStorageVolDelete">virStorageVolDelete</a> (<a href="libvirt-libvirt.html#virStorageVolPtr">virStorageVolPtr</a> vol, <br/> unsigned int flags); -int <a href="#virStorageVolFree">virStorageVolFree</a> (<a href="libvirt-libvirt.html#virStorageVolPtr">virStorageVolPtr</a> vol); +int <a href="#virSecretUndefine">virSecretUndefine</a> (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret); int <a href="#virConnectListInterfaces">virConnectListInterfaces</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> char ** const names, <br/> int maxnames); int <a href="#virDomainMemoryPeek">virDomainMemoryPeek</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> dom, <br/> unsigned long long start, <br/> size_t size, <br/> void * buffer, <br/> unsigned int flags); <a href="libvirt-libvirt.html#virNetworkPtr">virNetworkPtr</a> <a href="#virNetworkLookupByUUID">virNetworkLookupByUUID</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const unsigned char * uuid); @@ -229,14 +237,14 @@ int <a href="#virConnectDomainEventRegister">virConnectDomainEventRegister</a> ( int <a href="#virDomainGetVcpus">virDomainGetVcpus</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain, <br/> <a href="libvirt-libvirt.html#virVcpuInfoPtr">virVcpuInfoPtr</a> info, <br/> int maxinfo, <br/> unsigned char * cpumaps, <br/> int maplen); <a href="libvirt-libvirt.html#virNodeDevicePtr">virNodeDevicePtr</a> <a href="#virNodeDeviceLookupByName">virNodeDeviceLookupByName</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * name); int <a href="#virStoragePoolGetInfo">virStoragePoolGetInfo</a> (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br/> <a href="libvirt-libvirt.html#virStoragePoolInfoPtr">virStoragePoolInfoPtr</a> info); -int <a href="#virDomainResume">virDomainResume</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain); +typedef int <a href="#virEventRemoveHandleFunc">virEventRemoveHandleFunc</a> (int watch); int <a href="#virInterfaceRef">virInterfaceRef</a> (<a href="libvirt-libvirt.html#virInterfacePtr">virInterfacePtr</a> iface); const char * <a href="#virInterfaceGetMACString">virInterfaceGetMACString</a> (<a href="libvirt-libvirt.html#virInterfacePtr">virInterfacePtr</a> iface); int <a href="#virConnectNumOfDomains">virConnectNumOfDomains</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn); int <a href="#virStoragePoolRefresh">virStoragePoolRefresh</a> (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br/> unsigned int flags); int <a href="#virConnectNumOfDefinedDomains">virConnectNumOfDefinedDomains</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn); <a href="libvirt-libvirt.html#virStorageVolPtr">virStorageVolPtr</a> <a href="#virStorageVolCreateXMLFrom">virStorageVolCreateXMLFrom</a> (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br/> const char * xmldesc, <br/> <a href="libvirt-libvirt.html#virStorageVolPtr">virStorageVolPtr</a> clonevol, <br/> unsigned int flags); -int <a href="#virDomainUndefine">virDomainUndefine</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain); +int <a href="#virConnectClose">virConnectClose</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn); int <a href="#virDomainReboot">virDomainReboot</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain, <br/> unsigned int flags); int <a href="#virNetworkGetUUIDString">virNetworkGetUUIDString</a> (<a href="libvirt-libvirt.html#virNetworkPtr">virNetworkPtr</a> network, <br/> char * buf); <a href="libvirt-libvirt.html#virNetworkPtr">virNetworkPtr</a> <a href="#virNetworkLookupByName">virNetworkLookupByName</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * name); @@ -253,6 +261,7 @@ typedef int <a href="#virConnectAuthCallbackPtr">virConnectAuthCallbackPtr</a> ( int <a href="#virDomainAttachDevice">virDomainAttachDevice</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain, <br/> const char * xml); char * <a href="#virConnectGetURI">virConnectGetURI</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn); <a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> <a href="#virConnectOpenReadOnly">virConnectOpenReadOnly</a> (const char * name); +<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> <a href="#virSecretDefineXML">virSecretDefineXML</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * xml); int <a href="#virNetworkFree">virNetworkFree</a> (<a href="libvirt-libvirt.html#virNetworkPtr">virNetworkPtr</a> network); <a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> <a href="#virStoragePoolLookupByUUID">virStoragePoolLookupByUUID</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const unsigned char * uuid); typedef int <a href="#virEventAddHandleFunc">virEventAddHandleFunc</a> (int fd, <br/> int event, <br/> <a href="libvirt-libvirt.html#virEventHandleCallback">virEventHandleCallback</a> cb, <br/> void * opaque, <br/> <a href="libvirt-libvirt.html#virFreeCallback">virFreeCallback</a> ff); @@ -265,6 +274,7 @@ int <a href="#virNodeDeviceNumOfCaps">virNodeDeviceNumOfCaps</a> (<a href="libv <a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> <a href="#virNetworkGetConnect">virNetworkGetConnect</a> (<a href="libvirt-libvirt.html#virNetworkPtr">virNetworkPtr</a> net); unsigned long long <a href="#virNodeGetFreeMemory">virNodeGetFreeMemory</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn); int <a href="#virInterfaceDestroy">virInterfaceDestroy</a> (<a href="libvirt-libvirt.html#virInterfacePtr">virInterfacePtr</a> iface, <br/> unsigned int flags); +int <a href="#virSecretSetValue">virSecretSetValue</a> (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret, <br/> const unsigned char * value, <br/> size_t value_size); <a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> <a href="#virStorageVolGetConnect">virStorageVolGetConnect</a> (<a href="libvirt-libvirt.html#virStorageVolPtr">virStorageVolPtr</a> vol); int <a href="#virNodeNumOfDevices">virNodeNumOfDevices</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * cap, <br/> unsigned int flags); int <a href="#virStoragePoolDestroy">virStoragePoolDestroy</a> (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool); @@ -276,6 +286,7 @@ int <a href="#virConnectGetMaxVcpus">virConnectGetMaxVcpus</a> (<a href="libvir int <a href="#virDomainGetUUIDString">virDomainGetUUIDString</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain, <br/> char * buf); <a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> <a href="#virDomainGetConnect">virDomainGetConnect</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> dom); int <a href="#virConnectNumOfDefinedStoragePools">virConnectNumOfDefinedStoragePools</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn); +int <a href="#virSecretFree">virSecretFree</a> (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret); int <a href="#virNodeListDevices">virNodeListDevices</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * cap, <br/> char ** const names, <br/> int maxnames, <br/> unsigned int flags); const char * <a href="#virNodeDeviceGetParent">virNodeDeviceGetParent</a> (<a href="libvirt-libvirt.html#virNodeDevicePtr">virNodeDevicePtr</a> dev); <a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> <a href="#virConnectOpen">virConnectOpen</a> (const char * name); @@ -284,13 +295,16 @@ int <a href="#virNodeDeviceRef">virNodeDeviceRef</a> (<a href="libvirt-libvirt. int <a href="#virInterfaceUndefine">virInterfaceUndefine</a> (<a href="libvirt-libvirt.html#virInterfacePtr">virInterfacePtr</a> iface); int <a href="#virDomainSetVcpus">virDomainSetVcpus</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain, <br/> unsigned int nvcpus); int <a href="#virDomainRef">virDomainRef</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain); +int <a href="#virConnectListSecrets">virConnectListSecrets</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> char ** uuids, <br/> int maxuuids); int <a href="#virConnectNumOfInterfaces">virConnectNumOfInterfaces</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn); unsigned int <a href="#virDomainGetID">virDomainGetID</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain); +int <a href="#virSecretRef">virSecretRef</a> (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret); int <a href="#virDomainBlockPeek">virDomainBlockPeek</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> dom, <br/> const char * path, <br/> unsigned long long offset, <br/> size_t size, <br/> void * buffer, <br/> unsigned int flags); typedef int <a href="#virEventAddTimeoutFunc">virEventAddTimeoutFunc</a> (int timeout, <br/> <a href="libvirt-libvirt.html#virEventTimeoutCallback">virEventTimeoutCallback</a> cb, <br/> void * opaque, <br/> <a href="libvirt-libvirt.html#virFreeCallback">virFreeCallback</a> ff); <a href="libvirt-libvirt.html#virInterfacePtr">virInterfacePtr</a> <a href="#virInterfaceLookupByName">virInterfaceLookupByName</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * name); int <a href="#virDomainInterfaceStats">virDomainInterfaceStats</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> dom, <br/> const char * path, <br/> <a href="libvirt-libvirt.html#virDomainInterfaceStatsPtr">virDomainInterfaceStatsPtr</a> stats, <br/> size_t size); int <a href="#virConnectListNetworks">virConnectListNetworks</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> char ** const names, <br/> int maxnames); +unsigned char * <a href="#virSecretGetValue">virSecretGetValue</a> (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret, <br/> size_t * value_size); <a href="libvirt-libvirt.html#virStorageVolPtr">virStorageVolPtr</a> <a href="#virStorageVolLookupByKey">virStorageVolLookupByKey</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * key); </pre> </div> @@ -642,6 +656,16 @@ The content of this structure is not made public by the API. </pre><p/> </div> <hr/> + <div class="refsect2" lang="en"><h3><a name="virSecret">Structure </a>virSecret</h3><pre class="programlisting">struct _virSecret { +The content of this structure is not made public by the API. +} virSecret; +</pre><p/> +</div> + <hr/> + <div class="refsect2" lang="en"><h3><a name="virSecretPtr">Typedef </a>virSecretPtr</h3><pre class="programlisting"><a href="libvirt-libvirt.html#virSecret">virSecret</a> * virSecretPtr; +</pre><p/> +</div> + <hr/> <div class="refsect2" lang="en"><h3><a name="virSecurityLabel">Structure </a>virSecurityLabel</h3><pre class="programlisting">struct _virSecurityLabel { The content of this structure is not made public by the API. } virSecurityLabel; @@ -890,6 +914,10 @@ The content of this structure is not made public by the API. </pre><p>Collect the list of active networks, and store their names in @names</p> <div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to the hypervisor connection</td></tr><tr><td><span class="term"><i><tt>names</tt></i>:</span></td><td>array to collect the list of names of active networks</td></tr><tr><td><span class="term"><i><tt>maxnames</tt></i>:</span></td><td>size of @names</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number of networks found or -1 in case of error</td></tr></tbody></table></div></div> <hr/> + <div class="refsect2" lang="en"><h3><a name="virConnectListSecrets"/>virConnectListSecrets ()</h3><pre class="programlisting">int virConnectListSecrets (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> char ** uuids, <br/> int maxuuids)<br/> +</pre><p>List UUIDs of defined secrets, store pointers to names in uuids.</p> +<div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td><a href="libvirt-libvirt.html#virConnect">virConnect</a> connection</td></tr><tr><td><span class="term"><i><tt>uuids</tt></i>:</span></td><td>Pointer to an array to store the UUIDs</td></tr><tr><td><span class="term"><i><tt>maxuuids</tt></i>:</span></td><td>size of the array.</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number of UUIDs provided in the array, or -1 on failure.</td></tr></tbody></table></div></div> + <hr/> <div class="refsect2" lang="en"><h3><a name="virConnectListStoragePools"/>virConnectListStoragePools ()</h3><pre class="programlisting">int virConnectListStoragePools (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> char ** const names, <br/> int maxnames)<br/> </pre><p>Provides the list of names of active storage pools upto maxnames. If there are more than maxnames, the remaining names will be silently ignored.</p> <div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to hypervisor connection</td></tr><tr><td><span class="term"><i><tt>names</tt></i>:</span></td><td>array of char * to fill with pool names (allocated by caller)</td></tr><tr><td><span class="term"><i><tt>maxnames</tt></i>:</span></td><td>size of the names array</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 on success, -1 on error</td></tr></tbody></table></div></div> @@ -922,6 +950,10 @@ The content of this structure is not made public by the API. </pre><p>Provides the number of active networks.</p> <div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to the hypervisor connection</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number of network found or -1 in case of error</td></tr></tbody></table></div></div> <hr/> + <div class="refsect2" lang="en"><h3><a name="virConnectNumOfSecrets"/>virConnectNumOfSecrets ()</h3><pre class="programlisting">int virConnectNumOfSecrets (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn)<br/> +</pre><p>Fetch number of currently defined secrets.</p> +<div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td><a href="libvirt-libvirt.html#virConnect">virConnect</a> connection</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number currently defined secrets.</td></tr></tbody></table></div></div> + <hr/> <div class="refsect2" lang="en"><h3><a name="virConnectNumOfStoragePools"/>virConnectNumOfStoragePools ()</h3><pre class="programlisting">int virConnectNumOfStoragePools (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn)<br/> </pre><p>Provides the number of active storage pools</p> <div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to hypervisor connection</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number of pools found, or -1 on error</td></tr></tbody></table></div></div> @@ -1338,6 +1370,46 @@ The content of this structure is not made public by the API. </pre><p>Provides the number of node devices. If the optional 'cap' argument is non-NULL, then the count will be restricted to devices with the specified capability</p> <div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to the hypervisor connection</td></tr><tr><td><span class="term"><i><tt>cap</tt></i>:</span></td><td>capability name</td></tr><tr><td><span class="term"><i><tt>flags</tt></i>:</span></td><td>flags (unused, pass 0)</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number of node devices or -1 in case of error</td></tr></tbody></table></div></div> <hr/> + <div class="refsect2" lang="en"><h3><a name="virSecretDefineXML"/>virSecretDefineXML ()</h3><pre class="programlisting"><a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> virSecretDefineXML (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * xml)<br/> +</pre><p>If XML specifies an UUID, locates the specified secret and replaces all attributes of the secret specified by UUID by attributes specified in xml (any attributes not specified in xml are discarded). Otherwise, creates a new secret with an automatically chosen UUID, and initializes its attributes from xml.</p> +<div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td><a href="libvirt-libvirt.html#virConnect">virConnect</a> connection</td></tr><tr><td><span class="term"><i><tt>xml</tt></i>:</span></td><td>XML describing the secret.</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>a the secret on success, NULL on failure.</td></tr></tbody></table></div></div> + <hr/> + <div class="refsect2" lang="en"><h3><a name="virSecretFree"/>virSecretFree ()</h3><pre class="programlisting">int virSecretFree (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret)<br/> +</pre><p>Release the secret handle. The underlying secret continues to exist.</p> +<div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>secret</tt></i>:</span></td><td>pointer to a secret</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 on success, or -1 on error</td></tr></tbody></table></div></div> + <hr/> + <div class="refsect2" lang="en"><h3><a name="virSecretGetConnect"/>virSecretGetConnect ()</h3><pre class="programlisting"><a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> virSecretGetConnect (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret)<br/> +</pre><p>Provides the connection pointer associated with a secret. The reference counter on the connection is not increased by this call. WARNING: When writing libvirt bindings in other languages, do not use this function. Instead, store the connection and the secret object together.</p> +<div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>secret</tt></i>:</span></td><td>A <a href="libvirt-libvirt.html#virSecret">virSecret</a> secret</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the <a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> or NULL in case of failure.</td></tr></tbody></table></div></div> + <hr/> + <div class="refsect2" lang="en"><h3><a name="virSecretGetUUIDString"/>virSecretGetUUIDString ()</h3><pre class="programlisting">char * virSecretGetUUIDString (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret)<br/> +</pre><p>Fetches the UUID of the secret.</p> +<div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>secret</tt></i>:</span></td><td>A <a href="libvirt-libvirt.html#virSecret">virSecret</a> secret</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>ID of the secret (not necessarily in the UUID format) on success, NULL on failure. The caller must free() the ID.</td></tr></tbody></table></div></div> + <hr/> + <div class="refsect2" lang="en"><h3><a name="virSecretGetValue"/>virSecretGetValue ()</h3><pre class="programlisting">unsigned char * virSecretGetValue (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret, <br/> size_t * value_size)<br/> +</pre><p>Fetches the value of a secret.</p> +<div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>secret</tt></i>:</span></td><td>A <a href="libvirt-libvirt.html#virSecret">virSecret</a> connection</td></tr><tr><td><span class="term"><i><tt>value_size</tt></i>:</span></td><td>Place for storing size of the secret value</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the secret value on success, NULL on failure. The caller must free() the secret value.</td></tr></tbody></table></div></div> + <hr/> + <div class="refsect2" lang="en"><h3><a name="virSecretGetXMLDesc"/>virSecretGetXMLDesc ()</h3><pre class="programlisting">char * virSecretGetXMLDesc (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret)<br/> +</pre><p>Fetches an XML document describing attributes of the secret.</p> +<div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>secret</tt></i>:</span></td><td>A <a href="libvirt-libvirt.html#virSecret">virSecret</a> secret</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the XML document on success, NULL on failure. The caller must free() the XML.</td></tr></tbody></table></div></div> + <hr/> + <div class="refsect2" lang="en"><h3><a name="virSecretLookupByUUIDString"/>virSecretLookupByUUIDString ()</h3><pre class="programlisting"><a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> virSecretLookupByUUIDString (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * uuid)<br/> +</pre><p>Fetches a secret based on uuid.</p> +<div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td><a href="libvirt-libvirt.html#virConnect">virConnect</a> connection</td></tr><tr><td><span class="term"><i><tt>uuid</tt></i>:</span></td><td>ID of a secret</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the secret on success, or NULL on failure.</td></tr></tbody></table></div></div> + <hr/> + <div class="refsect2" lang="en"><h3><a name="virSecretRef"/>virSecretRef ()</h3><pre class="programlisting">int virSecretRef (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret)<br/> +</pre><p>Increment the reference count on the secret. For each additional call to this method, there shall be a corresponding call to <a href="libvirt-libvirt.html#virSecretFree">virSecretFree</a> to release the reference count, once the caller no longer needs the reference to this object. This method is typically useful for applications where multiple threads are using a connection, and it is required that the connection remain open until all threads have finished using it. ie, each new thread using a secret would increment the reference count.</p> +<div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>secret</tt></i>:</span></td><td>the secret to hold a reference on</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 in case of success, -1 in case of failure.</td></tr></tbody></table></div></div> + <hr/> + <div class="refsect2" lang="en"><h3><a name="virSecretSetValue"/>virSecretSetValue ()</h3><pre class="programlisting">int virSecretSetValue (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret, <br/> const unsigned char * value, <br/> size_t value_size)<br/> +</pre><p>Sets the value of a secret.</p> +<div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>secret</tt></i>:</span></td><td>A <a href="libvirt-libvirt.html#virSecret">virSecret</a> secret</td></tr><tr><td><span class="term"><i><tt>value</tt></i>:</span></td><td>Value of the secret</td></tr><tr><td><span class="term"><i><tt>value_size</tt></i>:</span></td><td>Size of the value</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 on success, -1 on failure.</td></tr></tbody></table></div></div> + <hr/> + <div class="refsect2" lang="en"><h3><a name="virSecretUndefine"/>virSecretUndefine ()</h3><pre class="programlisting">int virSecretUndefine (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret)<br/> +</pre><p>Deletes the specified secret. This does not free the associated <a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> object.</p> +<div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>secret</tt></i>:</span></td><td>A <a href="libvirt-libvirt.html#virSecret">virSecret</a> secret</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 on success, -1 on failure.</td></tr></tbody></table></div></div> + <hr/> <div class="refsect2" lang="en"><h3><a name="virStoragePoolBuild"/>virStoragePoolBuild ()</h3><pre class="programlisting">int virStoragePoolBuild (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br/> unsigned int flags)<br/> </pre><p>Build the underlying storage pool</p> <div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>pool</tt></i>:</span></td><td>pointer to storage pool</td></tr><tr><td><span class="term"><i><tt>flags</tt></i>:</span></td><td>future flags, use 0 for now</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 on success, or -1 upon failure</td></tr></tbody></table></div></div> diff --git a/docs/devhelp/libvirt-virterror.html b/docs/devhelp/libvirt-virterror.html index 88a8505..6865224 100644 --- a/docs/devhelp/libvirt-virterror.html +++ b/docs/devhelp/libvirt-virterror.html @@ -111,7 +111,8 @@ void <a href="#virConnResetLastError">virConnResetLastError</a> (<a href="libvi <a name="VIR_FROM_INTERFACE">VIR_FROM_INTERFACE</a> = 26 /* Error when operating on an interface */ <a name="VIR_FROM_ONE">VIR_FROM_ONE</a> = 27 /* Error from OpenNebula driver */ <a name="VIR_FROM_ESX">VIR_FROM_ESX</a> = 28 /* Error from ESX driver */ - <a name="VIR_FROM_PHYP">VIR_FROM_PHYP</a> = 29 /* Error from IBM power hypervisor */ + <a name="VIR_FROM_PHYP">VIR_FROM_PHYP</a> = 29 /* Error from IBM power hypervisor */ + <a name="VIR_FROM_SECRET">VIR_FROM_SECRET</a> = 30 /* Error from secret storage */ }; </pre><p/> </div> @@ -184,7 +185,10 @@ void <a href="#virConnResetLastError">virConnResetLastError</a> (<a href="libvi <a name="VIR_WAR_NO_INTERFACE">VIR_WAR_NO_INTERFACE</a> = 56 /* failed to start interface driver */ <a name="VIR_ERR_NO_INTERFACE">VIR_ERR_NO_INTERFACE</a> = 57 /* interface driver not running */ <a name="VIR_ERR_INVALID_INTERFACE">VIR_ERR_INVALID_INTERFACE</a> = 58 /* invalid interface object */ - <a name="VIR_ERR_MULTIPLE_INTERFACES">VIR_ERR_MULTIPLE_INTERFACES</a> = 59 /* more than one matching interface found */ + <a name="VIR_ERR_MULTIPLE_INTERFACES">VIR_ERR_MULTIPLE_INTERFACES</a> = 59 /* more than one matching interface found */ + <a name="VIR_WAR_NO_SECRET">VIR_WAR_NO_SECRET</a> = 60 /* failed to start secret storage */ + <a name="VIR_ERR_INVALID_SECRET">VIR_ERR_INVALID_SECRET</a> = 61 /* invalid secret */ + <a name="VIR_ERR_NO_SECRET">VIR_ERR_NO_SECRET</a> = 62 /* secret not found */ }; </pre><p/> </div> diff --git a/docs/html/libvirt-libvirt.html b/docs/html/libvirt-libvirt.html index aeba99a..af39639 100644 --- a/docs/html/libvirt-libvirt.html +++ b/docs/html/libvirt-libvirt.html @@ -57,6 +57,8 @@ typedef <a href="libvirt-libvirt.html#virNodeInfo">virNodeInfo</a> * <a name="vi typedef struct _virSchedParameter <a href="#virSchedParameter">virSchedParameter</a> typedef <a href="libvirt-libvirt.html#virSchedParameter">virSchedParameter</a> * <a name="virSchedParameterPtr" id="virSchedParameterPtr">virSchedParameterPtr</a> typedef enum <a href="#virSchedParameterType">virSchedParameterType</a> +typedef struct _virSecret <a href="#virSecret">virSecret</a> +typedef <a href="libvirt-libvirt.html#virSecret">virSecret</a> * <a name="virSecretPtr" id="virSecretPtr">virSecretPtr</a> typedef struct _virSecurityLabel <a href="#virSecurityLabel">virSecurityLabel</a> typedef <a href="libvirt-libvirt.html#virSecurityLabel">virSecurityLabel</a> * <a name="virSecurityLabelPtr" id="virSecurityLabelPtr">virSecurityLabelPtr</a> typedef struct _virSecurityModel <a href="#virSecurityModel">virSecurityModel</a> @@ -102,6 +104,7 @@ int <a href="#virConnectListDefinedStoragePools">virConnectListDefinedStoragePoo int <a href="#virConnectListDomains">virConnectListDomains</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> int * ids, <br /> int maxids) int <a href="#virConnectListInterfaces">virConnectListInterfaces</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> char ** const names, <br /> int maxnames) int <a href="#virConnectListNetworks">virConnectListNetworks</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> char ** const names, <br /> int maxnames) +int <a href="#virConnectListSecrets">virConnectListSecrets</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> char ** uuids, <br /> int maxuuids) int <a href="#virConnectListStoragePools">virConnectListStoragePools</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> char ** const names, <br /> int maxnames) int <a href="#virConnectNumOfDefinedDomains">virConnectNumOfDefinedDomains</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn) int <a href="#virConnectNumOfDefinedInterfaces">virConnectNumOfDefinedInterfaces</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn) @@ -110,6 +113,7 @@ int <a href="#virConnectNumOfDefinedStoragePools">virConnectNumOfDefinedStorageP int <a href="#virConnectNumOfDomains">virConnectNumOfDomains</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn) int <a href="#virConnectNumOfInterfaces">virConnectNumOfInterfaces</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn) int <a href="#virConnectNumOfNetworks">virConnectNumOfNetworks</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn) +int <a href="#virConnectNumOfSecrets">virConnectNumOfSecrets</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn) int <a href="#virConnectNumOfStoragePools">virConnectNumOfStoragePools</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn) <a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> <a href="#virConnectOpen">virConnectOpen</a> (const char * name) <a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> <a href="#virConnectOpenAuth">virConnectOpenAuth</a> (const char * name, <br /> <a href="libvirt-libvirt.html#virConnectAuthPtr">virConnectAuthPtr</a> auth, <br /> int flags) @@ -241,6 +245,16 @@ int <a href="#virNodeGetInfo">virNodeGetInfo</a> (<a href="libvirt-libvirt.htm int <a href="#virNodeGetSecurityModel">virNodeGetSecurityModel</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> <a href="libvirt-libvirt.html#virSecurityModelPtr">virSecurityModelPtr</a> secmodel) int <a href="#virNodeListDevices">virNodeListDevices</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> const char * cap, <br /> char ** const names, <br /> int maxnames, <br /> unsigned int flags) int <a href="#virNodeNumOfDevices">virNodeNumOfDevices</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> const char * cap, <br /> unsigned int flags) +<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> <a href="#virSecretDefineXML">virSecretDefineXML</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> const char * xml) +int <a href="#virSecretFree">virSecretFree</a> (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret) +<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> <a href="#virSecretGetConnect">virSecretGetConnect</a> (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret) +char * <a href="#virSecretGetUUIDString">virSecretGetUUIDString</a> (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret) +unsigned char * <a href="#virSecretGetValue">virSecretGetValue</a> (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret, <br /> size_t * value_size) +char * <a href="#virSecretGetXMLDesc">virSecretGetXMLDesc</a> (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret) +<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> <a href="#virSecretLookupByUUIDString">virSecretLookupByUUIDString</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> const char * uuid) +int <a href="#virSecretRef">virSecretRef</a> (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret) +int <a href="#virSecretSetValue">virSecretSetValue</a> (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret, <br /> const unsigned char * value, <br /> size_t value_size) +int <a href="#virSecretUndefine">virSecretUndefine</a> (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret) int <a href="#virStoragePoolBuild">virStoragePoolBuild</a> (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br /> unsigned int flags) int <a href="#virStoragePoolCreate">virStoragePoolCreate</a> (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br /> unsigned int flags) <a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> <a href="#virStoragePoolCreateXML">virStoragePoolCreateXML</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> const char * xmlDesc, <br /> unsigned int flags) @@ -347,6 +361,9 @@ int <a href="#virStorageVolRef">virStorageVolRef</a> (<a href="libvirt-libvirt. } </pre></div><h3><a name="virSchedParameterType" id="virSchedParameterType"><code>virSchedParameterType</code></a></h3><div class="api"><pre>enum virSchedParameterType { </pre><table><tr><td><a name="VIR_DOMAIN_SCHED_FIELD_INT" id="VIR_DOMAIN_SCHED_FIELD_INT">VIR_DOMAIN_SCHED_FIELD_INT</a></td><td> = </td><td>1</td><td> : integer case</td></tr><tr><td><a name="VIR_DOMAIN_SCHED_FIELD_UINT" id="VIR_DOMAIN_SCHED_FIELD_UINT">VIR_DOMAIN_SCHED_FIELD_UINT</a></td><td> = </td><td>2</td><td> : unsigned integer case</td></tr><tr><td><a name="VIR_DOMAIN_SCHED_FIELD_LLONG" id="VIR_DOMAIN_SCHED_FIELD_LLONG">VIR_DOMAIN_SCHED_FIELD_LLONG</a></td><td> = </td><td>3</td><td> : long long case</td></tr><tr><td><a name="VIR_DOMAIN_SCHED_FIELD_ULLONG" id="VIR_DOMAIN_SCHED_FIELD_ULLONG">VIR_DOMAIN_SCHED_FIELD_ULLONG</a></td><td> = </td><td>4</td><td> : unsigned long long case</td></tr><tr><td><a name="VIR_DOMAIN_SCHED_FIELD_DOUBLE" id="VIR_DOMAIN_SCHED_FIELD_DOUBLE">VIR_DOMAIN_SCHED_FIELD_DOUBLE</a></td><td> = </td><td>5</td><td> : double case</td></tr><tr><td><a name="VIR_DOMAIN_SCHED_FIELD_BOOLEAN" id="VIR_DOMAIN_SCHED_FIELD_BOOLEAN">VIR_DOMAIN_SCHED_FIELD_BOOL! EAN</a></td><td> = </td><td>6</td><td> : boolean(character) case</td></tr></table><pre>} +</pre></div><h3><a name="virSecret" id="virSecret"><code>virSecret</code></a></h3><div class="api"><pre>struct virSecret{ +</pre><table><tr><td colspan="3">The content of this structure is not made public by the API</td></tr></table><pre> +} </pre></div><h3><a name="virSecurityLabel" id="virSecurityLabel"><code>virSecurityLabel</code></a></h3><div class="api"><pre>struct virSecurityLabel{ </pre><table><tr><td colspan="3">The content of this structure is not made public by the API</td></tr></table><pre> } @@ -401,7 +418,8 @@ int <a href="#virStorageVolRef">virStorageVolRef</a> (<a href="libvirt-libvirt. </pre><p>Provides the list of names of inactive storage pools upto maxnames. If there are more than maxnames, the remaining names will be silently ignored.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to hypervisor connection</td></tr><tr><td><span class="term"><i><tt>names</tt></i>:</span></td><td>array of char * to fill with pool names (allocated by caller)</td></tr><tr><td><span class="term"><i><tt>maxnames</tt></i>:</span></td><td>size of the names array</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 on success, -1 on error</td></tr></tbody></table></div><h3><a name="virConnectListDomains" id="virConnectListDomains"><code>virConnectListDomains</code></a></h3><pre class="programlisting">int virConnectListDomains (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> int * ids, <br /> int maxids)<br /> </pre><p>Collect the list of active domains, and store their ID in @maxids</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to the hypervisor connection</td></tr><tr><td><span class="term"><i><tt>ids</tt></i>:</span></td><td>array to collect the list of IDs of active domains</td></tr><tr><td><span class="term"><i><tt>maxids</tt></i>:</span></td><td>size of @ids</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number of domain found or -1 in case of error</td></tr></tbody></table></div><h3><a name="virConnectListInterfaces" id="virConnectListInterfaces"><code>virConnectListInterfaces</code></a></h3><pre class="programlisting">int virConnectListInterfaces (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> char ** const names, <br /> int maxnames)<br /> </pre><p>Collect the list of active physical host interfaces, and store their names in @names</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to the hypervisor connection</td></tr><tr><td><span class="term"><i><tt>names</tt></i>:</span></td><td>array to collect the list of names of interfaces</td></tr><tr><td><span class="term"><i><tt>maxnames</tt></i>:</span></td><td>size of @names</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number of interfaces found or -1 in case of error</td></tr></tbody></table></div><h3><a name="virConnectListNetworks" id="virConnectListNetworks"><code>virConnectListNetworks</code></a></h3><pre class="programlisting">int virConnectListNetworks (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> char ** const names, <br /> int maxnames)<br /> -</pre><p>Collect the list of active networks, and store their names in @names</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to the hypervisor connection</td></tr><tr><td><span class="term"><i><tt>names</tt></i>:</span></td><td>array to collect the list of names of active networks</td></tr><tr><td><span class="term"><i><tt>maxnames</tt></i>:</span></td><td>size of @names</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number of networks found or -1 in case of error</td></tr></tbody></table></div><h3><a name="virConnectListStoragePools" id="virConnectListStoragePools"><code>virConnectListStoragePools</code></a></h3><pre class="programlisting">int virConnectListStoragePools (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> char ** const names, <br /> int maxnames)<br /> +</pre><p>Collect the list of active networks, and store their names in @names</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to the hypervisor connection</td></tr><tr><td><span class="term"><i><tt>names</tt></i>:</span></td><td>array to collect the list of names of active networks</td></tr><tr><td><span class="term"><i><tt>maxnames</tt></i>:</span></td><td>size of @names</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number of networks found or -1 in case of error</td></tr></tbody></table></div><h3><a name="virConnectListSecrets" id="virConnectListSecrets"><code>virConnectListSecrets</code></a></h3><pre class="programlisting">int virConnectListSecrets (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> char ** uuids, <br /> int maxuuids)<br /> +</pre><p>List UUIDs of defined secrets, store pointers to names in uuids.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td><a href="libvirt-libvirt.html#virConnect">virConnect</a> connection</td></tr><tr><td><span class="term"><i><tt>uuids</tt></i>:</span></td><td>Pointer to an array to store the UUIDs</td></tr><tr><td><span class="term"><i><tt>maxuuids</tt></i>:</span></td><td>size of the array.</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number of UUIDs provided in the array, or -1 on failure.</td></tr></tbody></table></div><h3><a name="virConnectListStoragePools" id="virConnectListStoragePools"><code>virConnectListStoragePools</code></a></h3><pre class="programlisting">int virConnectListStoragePools (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> char ** const names, <br /> int maxnames)<br /> </pre><p>Provides the list of names of active storage pools upto maxnames. If there are more than maxnames, the remaining names will be silently ignored.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to hypervisor connection</td></tr><tr><td><span class="term"><i><tt>names</tt></i>:</span></td><td>array of char * to fill with pool names (allocated by caller)</td></tr><tr><td><span class="term"><i><tt>maxnames</tt></i>:</span></td><td>size of the names array</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 on success, -1 on error</td></tr></tbody></table></div><h3><a name="virConnectNumOfDefinedDomains" id="virConnectNumOfDefinedDomains"><code>virConnectNumOfDefinedDomains</code></a></h3><pre class="programlisting">int virConnectNumOfDefinedDomains (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn)<br /> </pre><p>Provides the number of defined but inactive domains.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to the hypervisor connection</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number of domain found or -1 in case of error</td></tr></tbody></table></div><h3><a name="virConnectNumOfDefinedInterfaces" id="virConnectNumOfDefinedInterfaces"><code>virConnectNumOfDefinedInterfaces</code></a></h3><pre class="programlisting">int virConnectNumOfDefinedInterfaces (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn)<br /> </pre><p>Provides the number of defined (inactive) interfaces on the physical host.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to the hypervisor connection</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number of defined interface found or -1 in case of error</td></tr></tbody></table></div><h3><a name="virConnectNumOfDefinedNetworks" id="virConnectNumOfDefinedNetworks"><code>virConnectNumOfDefinedNetworks</code></a></h3><pre class="programlisting">int virConnectNumOfDefinedNetworks (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn)<br /> @@ -409,7 +427,8 @@ int <a href="#virStorageVolRef">virStorageVolRef</a> (<a href="libvirt-libvirt. </pre><p>Provides the number of inactive storage pools</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to hypervisor connection</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number of pools found, or -1 on error</td></tr></tbody></table></div><h3><a name="virConnectNumOfDomains" id="virConnectNumOfDomains"><code>virConnectNumOfDomains</code></a></h3><pre class="programlisting">int virConnectNumOfDomains (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn)<br /> </pre><p>Provides the number of active domains.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to the hypervisor connection</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number of domain found or -1 in case of error</td></tr></tbody></table></div><h3><a name="virConnectNumOfInterfaces" id="virConnectNumOfInterfaces"><code>virConnectNumOfInterfaces</code></a></h3><pre class="programlisting">int virConnectNumOfInterfaces (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn)<br /> </pre><p>Provides the number of active interfaces on the physical host.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to the hypervisor connection</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number of active interfaces found or -1 in case of error</td></tr></tbody></table></div><h3><a name="virConnectNumOfNetworks" id="virConnectNumOfNetworks"><code>virConnectNumOfNetworks</code></a></h3><pre class="programlisting">int virConnectNumOfNetworks (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn)<br /> -</pre><p>Provides the number of active networks.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to the hypervisor connection</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number of network found or -1 in case of error</td></tr></tbody></table></div><h3><a name="virConnectNumOfStoragePools" id="virConnectNumOfStoragePools"><code>virConnectNumOfStoragePools</code></a></h3><pre class="programlisting">int virConnectNumOfStoragePools (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn)<br /> +</pre><p>Provides the number of active networks.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to the hypervisor connection</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number of network found or -1 in case of error</td></tr></tbody></table></div><h3><a name="virConnectNumOfSecrets" id="virConnectNumOfSecrets"><code>virConnectNumOfSecrets</code></a></h3><pre class="programlisting">int virConnectNumOfSecrets (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn)<br /> +</pre><p>Fetch number of currently defined secrets.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td><a href="libvirt-libvirt.html#virConnect">virConnect</a> connection</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number currently defined secrets.</td></tr></tbody></table></div><h3><a name="virConnectNumOfStoragePools" id="virConnectNumOfStoragePools"><code>virConnectNumOfStoragePools</code></a></h3><pre class="programlisting">int virConnectNumOfStoragePools (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn)<br /> </pre><p>Provides the number of active storage pools</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to hypervisor connection</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number of pools found, or -1 on error</td></tr></tbody></table></div><h3><a name="virConnectOpen" id="virConnectOpen"><code>virConnectOpen</code></a></h3><pre class="programlisting"><a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> virConnectOpen (const char * name)<br /> </pre><p>This function should be called first to get a connection to the Hypervisor and xen store</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>name</tt></i>:</span></td><td>URI of the hypervisor</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>a pointer to the hypervisor connection or NULL in case of error If @name is NULL then probing will be done to determine a suitable default driver to activate. This involves trying each hypervisor in turn until one successfully opens. If the LIBVIRT_DEFAULT_URI environment variable is set, then it will be used in preference to probing for a driver. If connecting to an unprivileged hypervisor driver which requires the libvirtd daemon to be active, it will automatically be launched if not already running. This can be prevented by setting the environment variable LIBVIRT_AUTOSTART=0 URIs are documented at http://libvirt.org/uri.html</td></tr></tbody>! </table></div><h3><a name="virConnectOpenAuth" id="virConnectOpenAuth"><code>virConnectOpenAuth</code></a></h3><pre class="programlisting"><a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> virConnectOpenAuth (const char * name, <br /> <a href="libvirt-libvirt.html#virConnectAuthPtr">virConnectAuthPtr</a> auth, <br /> int flags)<br /> </pre><p>This function should be called first to get a connection to the Hypervisor. If necessary, authentication will be performed fetching credentials via the callback See <a href="libvirt-libvirt.html#virConnectOpen">virConnectOpen</a> for notes about environment variables which can have an effect on opening drivers</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>name</tt></i>:</span></td><td>URI of the hypervisor</td></tr><tr><td><span class="term"><i><tt>auth</tt></i>:</span></td><td>Authenticate callback parameters</td></tr><tr><td><span class="term"><i><tt>flags</tt></i>:</span></td><td>Open flags</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>a pointer to the hypervisor connection or NULL in case of error URIs are documented at http://libvirt.org/uri.html</td></tr></tbody></table></div><h3><a name="virConnectOpenReadOnly" id="virConnectOpenReadOnly"><code>virConnectOpenReadOnly<! /code></a></h3><pre class="programlisting"><a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> virConnectOpenReadOnly (const char * name)<br /> @@ -522,7 +541,17 @@ int <a href="#virStorageVolRef">virStorageVolRef</a> (<a href="libvirt-libvirt. </pre><p>Extract hardware information about the node.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to the hypervisor connection</td></tr><tr><td><span class="term"><i><tt>info</tt></i>:</span></td><td>pointer to a <a href="libvirt-libvirt.html#virNodeInfo">virNodeInfo</a> structure allocated by the user</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 in case of success and -1 in case of failure.</td></tr></tbody></table></div><h3><a name="virNodeGetSecurityModel" id="virNodeGetSecurityModel"><code>virNodeGetSecurityModel</code></a></h3><pre class="programlisting">int virNodeGetSecurityModel (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> <a href="libvirt-libvirt.html#virSecurityModelPtr">virSecurityModelPtr</a> secmodel)<br /> </pre><p>Extract the security model of a hypervisor. The 'model' field in the @secmodel argument may be initialized to the empty string if the driver has not activated a security model.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>a connection object</td></tr><tr><td><span class="term"><i><tt>secmodel</tt></i>:</span></td><td>pointer to a <a href="libvirt-libvirt.html#virSecurityModel">virSecurityModel</a> structure</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 in case of success, -1 in case of failure</td></tr></tbody></table></div><h3><a name="virNodeListDevices" id="virNodeListDevices"><code>virNodeListDevices</code></a></h3><pre class="programlisting">int virNodeListDevices (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> const char * cap, <br /> char ** const names, <br /> int maxnames, <br /> unsi! gned int flags)<br /> </pre><p>Collect the list of node devices, and store their names in @names If the optional 'cap' argument is non-NULL, then the count will be restricted to devices with the specified capability</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to the hypervisor connection</td></tr><tr><td><span class="term"><i><tt>cap</tt></i>:</span></td><td>capability name</td></tr><tr><td><span class="term"><i><tt>names</tt></i>:</span></td><td>array to collect the list of node device names</td></tr><tr><td><span class="term"><i><tt>maxnames</tt></i>:</span></td><td>size of @names</td></tr><tr><td><span class="term"><i><tt>flags</tt></i>:</span></td><td>flags (unused, pass 0)</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number of node devices found or -1 in case of error</td></tr></tbody></table></div><h3><a name="virNodeNumOfDevices" id="virNodeNumOfDevices"! ><code>virNodeNumOfDevices</code></a></h3><pre class="programlisting">int virNodeNumOfDevices (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> const char * cap, <br /> unsigned int flags)<br /> -</pre><p>Provides the number of node devices. If the optional 'cap' argument is non-NULL, then the count will be restricted to devices with the specified capability</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to the hypervisor connection</td></tr><tr><td><span class="term"><i><tt>cap</tt></i>:</span></td><td>capability name</td></tr><tr><td><span class="term"><i><tt>flags</tt></i>:</span></td><td>flags (unused, pass 0)</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number of node devices or -1 in case of error</td></tr></tbody></table></div><h3><a name="virStoragePoolBuild" id="virStoragePoolBuild"><code>virStoragePoolBuild</code></a></h3><pre class="programlisting">int virStoragePoolBuild (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br /> unsigned int flags)<br /> +</pre><p>Provides the number of node devices. If the optional 'cap' argument is non-NULL, then the count will be restricted to devices with the specified capability</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to the hypervisor connection</td></tr><tr><td><span class="term"><i><tt>cap</tt></i>:</span></td><td>capability name</td></tr><tr><td><span class="term"><i><tt>flags</tt></i>:</span></td><td>flags (unused, pass 0)</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the number of node devices or -1 in case of error</td></tr></tbody></table></div><h3><a name="virSecretDefineXML" id="virSecretDefineXML"><code>virSecretDefineXML</code></a></h3><pre class="programlisting"><a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> virSecretDefineXML (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> const char * xml)<b! r /> +</pre><p>If XML specifies an UUID, locates the specified secret and replaces all attributes of the secret specified by UUID by attributes specified in xml (any attributes not specified in xml are discarded). Otherwise, creates a new secret with an automatically chosen UUID, and initializes its attributes from xml.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td><a href="libvirt-libvirt.html#virConnect">virConnect</a> connection</td></tr><tr><td><span class="term"><i><tt>xml</tt></i>:</span></td><td>XML describing the secret.</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>a the secret on success, NULL on failure.</td></tr></tbody></table></div><h3><a name="virSecretFree" id="virSecretFree"><code>virSecretFree</code></a></h3><pre class="programlisting">int virSecretFree (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret)<br /> +</pre><p>Release the secret handle. The underlying secret continues to exist.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>secret</tt></i>:</span></td><td>pointer to a secret</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 on success, or -1 on error</td></tr></tbody></table></div><h3><a name="virSecretGetConnect" id="virSecretGetConnect"><code>virSecretGetConnect</code></a></h3><pre class="programlisting"><a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> virSecretGetConnect (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret)<br /> +</pre><p>Provides the connection pointer associated with a secret. The reference counter on the connection is not increased by this call. WARNING: When writing libvirt bindings in other languages, do not use this function. Instead, store the connection and the secret object together.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>secret</tt></i>:</span></td><td>A <a href="libvirt-libvirt.html#virSecret">virSecret</a> secret</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the <a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> or NULL in case of failure.</td></tr></tbody></table></div><h3><a name="virSecretGetUUIDString" id="virSecretGetUUIDString"><code>virSecretGetUUIDString</code></a></h3><pre class="programlisting">char * virSecretGetUUIDString (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret)<br /> +</pre><p>Fetches the UUID of the secret.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>secret</tt></i>:</span></td><td>A <a href="libvirt-libvirt.html#virSecret">virSecret</a> secret</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>ID of the secret (not necessarily in the UUID format) on success, NULL on failure. The caller must free() the ID.</td></tr></tbody></table></div><h3><a name="virSecretGetValue" id="virSecretGetValue"><code>virSecretGetValue</code></a></h3><pre class="programlisting">unsigned char * virSecretGetValue (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret, <br /> size_t * value_size)<br /> +</pre><p>Fetches the value of a secret.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>secret</tt></i>:</span></td><td>A <a href="libvirt-libvirt.html#virSecret">virSecret</a> connection</td></tr><tr><td><span class="term"><i><tt>value_size</tt></i>:</span></td><td>Place for storing size of the secret value</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the secret value on success, NULL on failure. The caller must free() the secret value.</td></tr></tbody></table></div><h3><a name="virSecretGetXMLDesc" id="virSecretGetXMLDesc"><code>virSecretGetXMLDesc</code></a></h3><pre class="programlisting">char * virSecretGetXMLDesc (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret)<br /> +</pre><p>Fetches an XML document describing attributes of the secret.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>secret</tt></i>:</span></td><td>A <a href="libvirt-libvirt.html#virSecret">virSecret</a> secret</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the XML document on success, NULL on failure. The caller must free() the XML.</td></tr></tbody></table></div><h3><a name="virSecretLookupByUUIDString" id="virSecretLookupByUUIDString"><code>virSecretLookupByUUIDString</code></a></h3><pre class="programlisting"><a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> virSecretLookupByUUIDString (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> const char * uuid)<br /> +</pre><p>Fetches a secret based on uuid.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td><a href="libvirt-libvirt.html#virConnect">virConnect</a> connection</td></tr><tr><td><span class="term"><i><tt>uuid</tt></i>:</span></td><td>ID of a secret</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>the secret on success, or NULL on failure.</td></tr></tbody></table></div><h3><a name="virSecretRef" id="virSecretRef"><code>virSecretRef</code></a></h3><pre class="programlisting">int virSecretRef (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret)<br /> +</pre><p>Increment the reference count on the secret. For each additional call to this method, there shall be a corresponding call to <a href="libvirt-libvirt.html#virSecretFree">virSecretFree</a> to release the reference count, once the caller no longer needs the reference to this object. This method is typically useful for applications where multiple threads are using a connection, and it is required that the connection remain open until all threads have finished using it. ie, each new thread using a secret would increment the reference count.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>secret</tt></i>:</span></td><td>the secret to hold a reference on</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 in case of success, -1 in case of failure.</td></tr></tbody></table></div><h3><a name="virSecretSetValue" id="virSecretSetValue"><code>virSecretSetValue</code></a></h3><pre class="prog! ramlisting">int virSecretSetValue (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret, <br /> const unsigned char * value, <br /> size_t value_size)<br /> +</pre><p>Sets the value of a secret.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>secret</tt></i>:</span></td><td>A <a href="libvirt-libvirt.html#virSecret">virSecret</a> secret</td></tr><tr><td><span class="term"><i><tt>value</tt></i>:</span></td><td>Value of the secret</td></tr><tr><td><span class="term"><i><tt>value_size</tt></i>:</span></td><td>Size of the value</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 on success, -1 on failure.</td></tr></tbody></table></div><h3><a name="virSecretUndefine" id="virSecretUndefine"><code>virSecretUndefine</code></a></h3><pre class="programlisting">int virSecretUndefine (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret)<br /> +</pre><p>Deletes the specified secret. This does not free the associated <a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> object.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>secret</tt></i>:</span></td><td>A <a href="libvirt-libvirt.html#virSecret">virSecret</a> secret</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 on success, -1 on failure.</td></tr></tbody></table></div><h3><a name="virStoragePoolBuild" id="virStoragePoolBuild"><code>virStoragePoolBuild</code></a></h3><pre class="programlisting">int virStoragePoolBuild (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br /> unsigned int flags)<br /> </pre><p>Build the underlying storage pool</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>pool</tt></i>:</span></td><td>pointer to storage pool</td></tr><tr><td><span class="term"><i><tt>flags</tt></i>:</span></td><td>future flags, use 0 for now</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 on success, or -1 upon failure</td></tr></tbody></table></div><h3><a name="virStoragePoolCreate" id="virStoragePoolCreate"><code>virStoragePoolCreate</code></a></h3><pre class="programlisting">int virStoragePoolCreate (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br /> unsigned int flags)<br /> </pre><p>Starts an inactive storage pool</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>pool</tt></i>:</span></td><td>pointer to storage pool</td></tr><tr><td><span class="term"><i><tt>flags</tt></i>:</span></td><td>future flags, use 0 for now</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 on success, or -1 if it could not be started</td></tr></tbody></table></div><h3><a name="virStoragePoolCreateXML" id="virStoragePoolCreateXML"><code>virStoragePoolCreateXML</code></a></h3><pre class="programlisting"><a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> virStoragePoolCreateXML (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> const char * xmlDesc, <br /> unsigned int flags)<br /> </pre><p>Create a new storage based on its XML description. The pool is not persistent, so its definition will disappear when it is destroyed, or if the host is restarted</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to hypervisor connection</td></tr><tr><td><span class="term"><i><tt>xmlDesc</tt></i>:</span></td><td>XML description for new pool</td></tr><tr><td><span class="term"><i><tt>flags</tt></i>:</span></td><td>future flags, use 0 for now</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>a <a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> object, or NULL if creation failed</td></tr></tbody></table></div><h3><a name="virStoragePoolDefineXML" id="virStoragePoolDefineXML"><code>virStoragePoolDefineXML</code></a></h3><pre class="programlisting"><a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> virStoragePoo! lDefineXML (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> const char * xml, <br /> unsigned int flags)<br /> diff --git a/docs/html/libvirt-virterror.html b/docs/html/libvirt-virterror.html index c3cbe11..aac55a0 100644 --- a/docs/html/libvirt-virterror.html +++ b/docs/html/libvirt-virterror.html @@ -27,11 +27,11 @@ void <a href="#virSetErrorFunc">virSetErrorFunc</a> (void * userData, <br /> </pre><table><tr><td>int</td><td>code</td><td> : The error code, a <a href="libvirt-virterror.html#virErrorNumber">virErrorNumber</a></td></tr><tr><td>int</td><td>domain</td><td> : What part of the library raised this error</td></tr><tr><td>char *</td><td>message</td><td> : human-readable informative error message</td></tr><tr><td><a href="libvirt-virterror.html#virErrorLevel">virErrorLevel</a></td><td>level</td><td> : how consequent is the error</td></tr><tr><td><a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a></td><td>conn</td><td> : connection if available, deprecated see note above</td></tr><tr><td><a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a></td><td>dom</td><td> : domain if available, deprecated see note above</td></tr><tr><td>char *</td><td>str1</td><td> : extra string information</td></tr><tr><td>char *</td><td>str2</td><td> : extra string information</td></tr><tr><td>char *</td><td>str3</td><td> : extra string information</td></tr><tr><t! d>int</td><td>int1</td><td> : extra number information</td></tr><tr><td>int</td><td>int2</td><td> : extra number information</td></tr><tr><td><a href="libvirt-libvirt.html#virNetworkPtr">virNetworkPtr</a></td><td>net</td><td> : network if available, deprecated see note above</td></tr></table><pre> } </pre></div><h3><a name="virErrorDomain" id="virErrorDomain"><code>virErrorDomain</code></a></h3><div class="api"><pre>enum virErrorDomain { -</pre><table><tr><td><a name="VIR_FROM_NONE" id="VIR_FROM_NONE">VIR_FROM_NONE</a></td><td> = </td><td>0</td></tr><tr><td><a name="VIR_FROM_XEN" id="VIR_FROM_XEN">VIR_FROM_XEN</a></td><td> = </td><td>1</td><td> : Error at Xen hypervisor layer</td></tr><tr><td><a name="VIR_FROM_XEND" id="VIR_FROM_XEND">VIR_FROM_XEND</a></td><td> = </td><td>2</td><td> : Error at connection with xend daemon</td></tr><tr><td><a name="VIR_FROM_XENSTORE" id="VIR_FROM_XENSTORE">VIR_FROM_XENSTORE</a></td><td> = </td><td>3</td><td> : Error at connection with xen store</td></tr><tr><td><a name="VIR_FROM_SEXPR" id="VIR_FROM_SEXPR">VIR_FROM_SEXPR</a></td><td> = </td><td>4</td><td> : Error in the S-Expression code</td></tr><tr><td><a name="VIR_FROM_XML" id="VIR_FROM_XML">VIR_FROM_XML</a></td><td> = </td><td>5</td><td> : Error in the XML code</td></tr><tr><td><a name="VIR_FROM_DOM" id="VIR_FROM_DOM">VIR_FROM_DOM</a></td><td> = </td><td>6</td><td> : Error when operating on a domain</td></tr><tr><td><a name! ="VIR_FROM_RPC" id="VIR_FROM_RPC">VIR_FROM_RPC</a></td><td> = </td><td>7</td><td> : Error in the XML-RPC code</td></tr><tr><td><a name="VIR_FROM_PROXY" id="VIR_FROM_PROXY">VIR_FROM_PROXY</a></td><td> = </td><td>8</td><td> : Error in the proxy code</td></tr><tr><td><a name="VIR_FROM_CONF" id="VIR_FROM_CONF">VIR_FROM_CONF</a></td><td> = </td><td>9</td><td> : Error in the configuration file handling</td></tr><tr><td><a name="VIR_FROM_QEMU" id="VIR_FROM_QEMU">VIR_FROM_QEMU</a></td><td> = </td><td>10</td><td> : Error at the QEMU daemon</td></tr><tr><td><a name="VIR_FROM_NET" id="VIR_FROM_NET">VIR_FROM_NET</a></td><td> = </td><td>11</td><td> : Error when operating on a network</td></tr><tr><td><a name="VIR_FROM_TEST" id="VIR_FROM_TEST">VIR_FROM_TEST</a></td><td> = </td><td>12</td><td> : Error from test driver</td></tr><tr><td><a name="VIR_FROM_REMOTE" id="VIR_FROM_REMOTE">VIR_FROM_REMOTE</a></td><td> = </td><td>13</td><td> : Error from remote driver</td></tr><tr><td><a name="VIR_! FROM_OPENVZ" id="VIR_FROM_OPENVZ">VIR_FROM_OPENVZ</a></td><td> = </td> <td>14</td><td> : Error from OpenVZ driver</td></tr><tr><td><a name="VIR_FROM_XENXM" id="VIR_FROM_XENXM">VIR_FROM_XENXM</a></td><td> = </td><td>15</td><td> : Error at Xen XM layer</td></tr><tr><td><a name="VIR_FROM_STATS_LINUX" id="VIR_FROM_STATS_LINUX">VIR_FROM_STATS_LINUX</a></td><td> = </td><td>16</td><td> : Error in the Linux Stats code</td></tr><tr><td><a name="VIR_FROM_LXC" id="VIR_FROM_LXC">VIR_FROM_LXC</a></td><td> = </td><td>17</td><td> : Error from Linux Container driver</td></tr><tr><td><a name="VIR_FROM_STORAGE" id="VIR_FROM_STORAGE">VIR_FROM_STORAGE</a></td><td> = </td><td>18</td><td> : Error from storage driver</td></tr><tr><td><a name="VIR_FROM_NETWORK" id="VIR_FROM_NETWORK">VIR_FROM_NETWORK</a></td><td> = </td><td>19</td><td> : Error from network config</td></tr><tr><td><a name="VIR_FROM_DOMAIN" id="VIR_FROM_DOMAIN">VIR_FROM_DOMAIN</a></td><td> = </td><td>20</td><td> : Error from domain config</td></tr><tr><td><a name="VIR_FROM_UML" id="VIR_FROM_UML">VIR_FROM! _UML</a></td><td> = </td><td>21</td><td> : Error at the UML driver</td></tr><tr><td><a name="VIR_FROM_NODEDEV" id="VIR_FROM_NODEDEV">VIR_FROM_NODEDEV</a></td><td> = </td><td>22</td><td> : Error from node device monitor</td></tr><tr><td><a name="VIR_FROM_XEN_INOTIFY" id="VIR_FROM_XEN_INOTIFY">VIR_FROM_XEN_INOTIFY</a></td><td> = </td><td>23</td><td> : Error from xen inotify layer</td></tr><tr><td><a name="VIR_FROM_SECURITY" id="VIR_FROM_SECURITY">VIR_FROM_SECURITY</a></td><td> = </td><td>24</td><td> : Error from security framework</td></tr><tr><td><a name="VIR_FROM_VBOX" id="VIR_FROM_VBOX">VIR_FROM_VBOX</a></td><td> = </td><td>25</td><td> : Error from VirtualBox driver</td></tr><tr><td><a name="VIR_FROM_INTERFACE" id="VIR_FROM_INTERFACE">VIR_FROM_INTERFACE</a></td><td> = </td><td>26</td><td> : Error when operating on an interface</td></tr><tr><td><a name="VIR_FROM_ONE" id="VIR_FROM_ONE">VIR_FROM_ONE</a></td><td> = </td><td>27</td><td> : Error from OpenNebula driver</td></tr><! tr><td><a name="VIR_FROM_ESX" id="VIR_FROM_ESX">VIR_FROM_ESX</a></td>< td> = </td><td>28</td><td> : Error from ESX driver</td></tr><tr><td><a name="VIR_FROM_PHYP" id="VIR_FROM_PHYP">VIR_FROM_PHYP</a></td><td> = </td><td>29</td><td> : Error from IBM power hypervisor</td></tr></table><pre>} +</pre><table><tr><td><a name="VIR_FROM_NONE" id="VIR_FROM_NONE">VIR_FROM_NONE</a></td><td> = </td><td>0</td></tr><tr><td><a name="VIR_FROM_XEN" id="VIR_FROM_XEN">VIR_FROM_XEN</a></td><td> = </td><td>1</td><td> : Error at Xen hypervisor layer</td></tr><tr><td><a name="VIR_FROM_XEND" id="VIR_FROM_XEND">VIR_FROM_XEND</a></td><td> = </td><td>2</td><td> : Error at connection with xend daemon</td></tr><tr><td><a name="VIR_FROM_XENSTORE" id="VIR_FROM_XENSTORE">VIR_FROM_XENSTORE</a></td><td> = </td><td>3</td><td> : Error at connection with xen store</td></tr><tr><td><a name="VIR_FROM_SEXPR" id="VIR_FROM_SEXPR">VIR_FROM_SEXPR</a></td><td> = </td><td>4</td><td> : Error in the S-Expression code</td></tr><tr><td><a name="VIR_FROM_XML" id="VIR_FROM_XML">VIR_FROM_XML</a></td><td> = </td><td>5</td><td> : Error in the XML code</td></tr><tr><td><a name="VIR_FROM_DOM" id="VIR_FROM_DOM">VIR_FROM_DOM</a></td><td> = </td><td>6</td><td> : Error when operating on a domain</td></tr><tr><td><a name! ="VIR_FROM_RPC" id="VIR_FROM_RPC">VIR_FROM_RPC</a></td><td> = </td><td>7</td><td> : Error in the XML-RPC code</td></tr><tr><td><a name="VIR_FROM_PROXY" id="VIR_FROM_PROXY">VIR_FROM_PROXY</a></td><td> = </td><td>8</td><td> : Error in the proxy code</td></tr><tr><td><a name="VIR_FROM_CONF" id="VIR_FROM_CONF">VIR_FROM_CONF</a></td><td> = </td><td>9</td><td> : Error in the configuration file handling</td></tr><tr><td><a name="VIR_FROM_QEMU" id="VIR_FROM_QEMU">VIR_FROM_QEMU</a></td><td> = </td><td>10</td><td> : Error at the QEMU daemon</td></tr><tr><td><a name="VIR_FROM_NET" id="VIR_FROM_NET">VIR_FROM_NET</a></td><td> = </td><td>11</td><td> : Error when operating on a network</td></tr><tr><td><a name="VIR_FROM_TEST" id="VIR_FROM_TEST">VIR_FROM_TEST</a></td><td> = </td><td>12</td><td> : Error from test driver</td></tr><tr><td><a name="VIR_FROM_REMOTE" id="VIR_FROM_REMOTE">VIR_FROM_REMOTE</a></td><td> = </td><td>13</td><td> : Error from remote driver</td></tr><tr><td><a name="VIR_! FROM_OPENVZ" id="VIR_FROM_OPENVZ">VIR_FROM_OPENVZ</a></td><td> = </td> <td>14</td><td> : Error from OpenVZ driver</td></tr><tr><td><a name="VIR_FROM_XENXM" id="VIR_FROM_XENXM">VIR_FROM_XENXM</a></td><td> = </td><td>15</td><td> : Error at Xen XM layer</td></tr><tr><td><a name="VIR_FROM_STATS_LINUX" id="VIR_FROM_STATS_LINUX">VIR_FROM_STATS_LINUX</a></td><td> = </td><td>16</td><td> : Error in the Linux Stats code</td></tr><tr><td><a name="VIR_FROM_LXC" id="VIR_FROM_LXC">VIR_FROM_LXC</a></td><td> = </td><td>17</td><td> : Error from Linux Container driver</td></tr><tr><td><a name="VIR_FROM_STORAGE" id="VIR_FROM_STORAGE">VIR_FROM_STORAGE</a></td><td> = </td><td>18</td><td> : Error from storage driver</td></tr><tr><td><a name="VIR_FROM_NETWORK" id="VIR_FROM_NETWORK">VIR_FROM_NETWORK</a></td><td> = </td><td>19</td><td> : Error from network config</td></tr><tr><td><a name="VIR_FROM_DOMAIN" id="VIR_FROM_DOMAIN">VIR_FROM_DOMAIN</a></td><td> = </td><td>20</td><td> : Error from domain config</td></tr><tr><td><a name="VIR_FROM_UML" id="VIR_FROM_UML">VIR_FROM! _UML</a></td><td> = </td><td>21</td><td> : Error at the UML driver</td></tr><tr><td><a name="VIR_FROM_NODEDEV" id="VIR_FROM_NODEDEV">VIR_FROM_NODEDEV</a></td><td> = </td><td>22</td><td> : Error from node device monitor</td></tr><tr><td><a name="VIR_FROM_XEN_INOTIFY" id="VIR_FROM_XEN_INOTIFY">VIR_FROM_XEN_INOTIFY</a></td><td> = </td><td>23</td><td> : Error from xen inotify layer</td></tr><tr><td><a name="VIR_FROM_SECURITY" id="VIR_FROM_SECURITY">VIR_FROM_SECURITY</a></td><td> = </td><td>24</td><td> : Error from security framework</td></tr><tr><td><a name="VIR_FROM_VBOX" id="VIR_FROM_VBOX">VIR_FROM_VBOX</a></td><td> = </td><td>25</td><td> : Error from VirtualBox driver</td></tr><tr><td><a name="VIR_FROM_INTERFACE" id="VIR_FROM_INTERFACE">VIR_FROM_INTERFACE</a></td><td> = </td><td>26</td><td> : Error when operating on an interface</td></tr><tr><td><a name="VIR_FROM_ONE" id="VIR_FROM_ONE">VIR_FROM_ONE</a></td><td> = </td><td>27</td><td> : Error from OpenNebula driver</td></tr><! tr><td><a name="VIR_FROM_ESX" id="VIR_FROM_ESX">VIR_FROM_ESX</a></td>< td> = </td><td>28</td><td> : Error from ESX driver</td></tr><tr><td><a name="VIR_FROM_PHYP" id="VIR_FROM_PHYP">VIR_FROM_PHYP</a></td><td> = </td><td>29</td><td> : Error from IBM power hypervisor</td></tr><tr><td><a name="VIR_FROM_SECRET" id="VIR_FROM_SECRET">VIR_FROM_SECRET</a></td><td> = </td><td>30</td><td> : Error from secret storage</td></tr></table><pre>} </pre></div><h3><a name="virErrorLevel" id="virErrorLevel"><code>virErrorLevel</code></a></h3><div class="api"><pre>enum virErrorLevel { </pre><table><tr><td><a name="VIR_ERR_NONE" id="VIR_ERR_NONE">VIR_ERR_NONE</a></td><td> = </td><td>0</td></tr><tr><td><a name="VIR_ERR_WARNING" id="VIR_ERR_WARNING">VIR_ERR_WARNING</a></td><td> = </td><td>1</td><td> : A simple warning</td></tr><tr><td><a name="VIR_ERR_ERROR" id="VIR_ERR_ERROR">VIR_ERR_ERROR</a></td><td> = </td><td>2</td><td> : An error</td></tr></table><pre>} </pre></div><h3><a name="virErrorNumber" id="virErrorNumber"><code>virErrorNumber</code></a></h3><div class="api"><pre>enum virErrorNumber { -</pre><table><tr><td><a name="VIR_ERR_OK" id="VIR_ERR_OK">VIR_ERR_OK</a></td><td> = </td><td>0</td></tr><tr><td><a name="VIR_ERR_INTERNAL_ERROR" id="VIR_ERR_INTERNAL_ERROR">VIR_ERR_INTERNAL_ERROR</a></td><td> = </td><td>1</td><td> : internal error</td></tr><tr><td><a name="VIR_ERR_NO_MEMORY" id="VIR_ERR_NO_MEMORY">VIR_ERR_NO_MEMORY</a></td><td> = </td><td>2</td><td> : memory allocation failure</td></tr><tr><td><a name="VIR_ERR_NO_SUPPORT" id="VIR_ERR_NO_SUPPORT">VIR_ERR_NO_SUPPORT</a></td><td> = </td><td>3</td><td> : no support for this function</td></tr><tr><td><a name="VIR_ERR_UNKNOWN_HOST" id="VIR_ERR_UNKNOWN_HOST">VIR_ERR_UNKNOWN_HOST</a></td><td> = </td><td>4</td><td> : could not resolve hostname</td></tr><tr><td><a name="VIR_ERR_NO_CONNECT" id="VIR_ERR_NO_CONNECT">VIR_ERR_NO_CONNECT</a></td><td> = </td><td>5</td><td> : can't connect to hypervisor</td></tr><tr><td><a name="VIR_ERR_INVALID_CONN" id="VIR_ERR_INVALID_CONN">VIR_ERR_INVALID_CONN</a></td><td> = </td><td>6</t! d><td> : invalid connection object</td></tr><tr><td><a name="VIR_ERR_INVALID_DOMAIN" id="VIR_ERR_INVALID_DOMAIN">VIR_ERR_INVALID_DOMAIN</a></td><td> = </td><td>7</td><td> : invalid domain object</td></tr><tr><td><a name="VIR_ERR_INVALID_ARG" id="VIR_ERR_INVALID_ARG">VIR_ERR_INVALID_ARG</a></td><td> = </td><td>8</td><td> : invalid function argument</td></tr><tr><td><a name="VIR_ERR_OPERATION_FAILED" id="VIR_ERR_OPERATION_FAILED">VIR_ERR_OPERATION_FAILED</a></td><td> = </td><td>9</td><td> : a command to hypervisor failed</td></tr><tr><td><a name="VIR_ERR_GET_FAILED" id="VIR_ERR_GET_FAILED">VIR_ERR_GET_FAILED</a></td><td> = </td><td>10</td><td> : a HTTP GET command to failed</td></tr><tr><td><a name="VIR_ERR_POST_FAILED" id="VIR_ERR_POST_FAILED">VIR_ERR_POST_FAILED</a></td><td> = </td><td>11</td><td> : a HTTP POST command to failed</td></tr><tr><td><a name="VIR_ERR_HTTP_ERROR" id="VIR_ERR_HTTP_ERROR">VIR_ERR_HTTP_ERROR</a></td><td> = </td><td>12</td><td> : unexpected HTTP erro! r code</td></tr><tr><td><a name="VIR_ERR_SEXPR_SERIAL" id="VIR_ERR_SEX PR_SERIAL">VIR_ERR_SEXPR_SERIAL</a></td><td> = </td><td>13</td><td> : failure to serialize an S-Expr</td></tr><tr><td><a name="VIR_ERR_NO_XEN" id="VIR_ERR_NO_XEN">VIR_ERR_NO_XEN</a></td><td> = </td><td>14</td><td> : could not open Xen hypervisor control</td></tr><tr><td><a name="VIR_ERR_XEN_CALL" id="VIR_ERR_XEN_CALL">VIR_ERR_XEN_CALL</a></td><td> = </td><td>15</td><td> : failure doing an hypervisor call</td></tr><tr><td><a name="VIR_ERR_OS_TYPE" id="VIR_ERR_OS_TYPE">VIR_ERR_OS_TYPE</a></td><td> = </td><td>16</td><td> : unknown OS type</td></tr><tr><td><a name="VIR_ERR_NO_KERNEL" id="VIR_ERR_NO_KERNEL">VIR_ERR_NO_KERNEL</a></td><td> = </td><td>17</td><td> : missing kernel information</td></tr><tr><td><a name="VIR_ERR_NO_ROOT" id="VIR_ERR_NO_ROOT">VIR_ERR_NO_ROOT</a></td><td> = </td><td>18</td><td> : missing root device information</td></tr><tr><td><a name="VIR_ERR_NO_SOURCE" id="VIR_ERR_NO_SOURCE">VIR_ERR_NO_SOURCE</a></td><td> = </td><td>19</td><td> : missing source device ! information</td></tr><tr><td><a name="VIR_ERR_NO_TARGET" id="VIR_ERR_NO_TARGET">VIR_ERR_NO_TARGET</a></td><td> = </td><td>20</td><td> : missing target device information</td></tr><tr><td><a name="VIR_ERR_NO_NAME" id="VIR_ERR_NO_NAME">VIR_ERR_NO_NAME</a></td><td> = </td><td>21</td><td> : missing domain name information</td></tr><tr><td><a name="VIR_ERR_NO_OS" id="VIR_ERR_NO_OS">VIR_ERR_NO_OS</a></td><td> = </td><td>22</td><td> : missing domain OS information</td></tr><tr><td><a name="VIR_ERR_NO_DEVICE" id="VIR_ERR_NO_DEVICE">VIR_ERR_NO_DEVICE</a></td><td> = </td><td>23</td><td> : missing domain devices information</td></tr><tr><td><a name="VIR_ERR_NO_XENSTORE" id="VIR_ERR_NO_XENSTORE">VIR_ERR_NO_XENSTORE</a></td><td> = </td><td>24</td><td> : could not open Xen Store control</td></tr><tr><td><a name="VIR_ERR_DRIVER_FULL" id="VIR_ERR_DRIVER_FULL">VIR_ERR_DRIVER_FULL</a></td><td> = </td><td>25</td><td> : too many drivers registered</td></tr><tr><td><a name="VIR_ERR_CALL_FAILED"! id="VIR_ERR_CALL_FAILED">VIR_ERR_CALL_FAILED</a></td><td> = </td><td> 26</td><td> : not supported by the drivers (DEPRECATED)</td></tr><tr><td><a name="VIR_ERR_XML_ERROR" id="VIR_ERR_XML_ERROR">VIR_ERR_XML_ERROR</a></td><td> = </td><td>27</td><td> : an XML description is not well formed or broken</td></tr><tr><td><a name="VIR_ERR_DOM_EXIST" id="VIR_ERR_DOM_EXIST">VIR_ERR_DOM_EXIST</a></td><td> = </td><td>28</td><td> : the domain already exist</td></tr><tr><td><a name="VIR_ERR_OPERATION_DENIED" id="VIR_ERR_OPERATION_DENIED">VIR_ERR_OPERATION_DENIED</a></td><td> = </td><td>29</td><td> : operation forbidden on read-only connections</td></tr><tr><td><a name="VIR_ERR_OPEN_FAILED" id="VIR_ERR_OPEN_FAILED">VIR_ERR_OPEN_FAILED</a></td><td> = </td><td>30</td><td> : failed to open a conf file</td></tr><tr><td><a name="VIR_ERR_READ_FAILED" id="VIR_ERR_READ_FAILED">VIR_ERR_READ_FAILED</a></td><td> = </td><td>31</td><td> : failed to read a conf file</td></tr><tr><td><a name="VIR_ERR_PARSE_FAILED" id="VIR_ERR_PARSE_FAILED">VIR_ERR_PARSE_FAILED</a></td><td> ! = </td><td>32</td><td> : failed to parse a conf file</td></tr><tr><td><a name="VIR_ERR_CONF_SYNTAX" id="VIR_ERR_CONF_SYNTAX">VIR_ERR_CONF_SYNTAX</a></td><td> = </td><td>33</td><td> : failed to parse the syntax of a conf file</td></tr><tr><td><a name="VIR_ERR_WRITE_FAILED" id="VIR_ERR_WRITE_FAILED">VIR_ERR_WRITE_FAILED</a></td><td> = </td><td>34</td><td> : failed to write a conf file</td></tr><tr><td><a name="VIR_ERR_XML_DETAIL" id="VIR_ERR_XML_DETAIL">VIR_ERR_XML_DETAIL</a></td><td> = </td><td>35</td><td> : detail of an XML error</td></tr><tr><td><a name="VIR_ERR_INVALID_NETWORK" id="VIR_ERR_INVALID_NETWORK">VIR_ERR_INVALID_NETWORK</a></td><td> = </td><td>36</td><td> : invalid network object</td></tr><tr><td><a name="VIR_ERR_NETWORK_EXIST" id="VIR_ERR_NETWORK_EXIST">VIR_ERR_NETWORK_EXIST</a></td><td> = </td><td>37</td><td> : the network already exist</td></tr><tr><td><a name="VIR_ERR_SYSTEM_ERROR" id="VIR_ERR_SYSTEM_ERROR">VIR_ERR_SYSTEM_ERROR</a></td><td> = </td><td>38</td! ><td> : general system call failure</td></tr><tr><td><a name="VIR_ERR_ RPC" id="VIR_ERR_RPC">VIR_ERR_RPC</a></td><td> = </td><td>39</td><td> : some sort of RPC error</td></tr><tr><td><a name="VIR_ERR_GNUTLS_ERROR" id="VIR_ERR_GNUTLS_ERROR">VIR_ERR_GNUTLS_ERROR</a></td><td> = </td><td>40</td><td> : error from a GNUTLS call</td></tr><tr><td><a name="VIR_WAR_NO_NETWORK" id="VIR_WAR_NO_NETWORK">VIR_WAR_NO_NETWORK</a></td><td> = </td><td>41</td><td> : failed to start network</td></tr><tr><td><a name="VIR_ERR_NO_DOMAIN" id="VIR_ERR_NO_DOMAIN">VIR_ERR_NO_DOMAIN</a></td><td> = </td><td>42</td><td> : domain not found or unexpectedly disappeared</td></tr><tr><td><a name="VIR_ERR_NO_NETWORK" id="VIR_ERR_NO_NETWORK">VIR_ERR_NO_NETWORK</a></td><td> = </td><td>43</td><td> : network not found</td></tr><tr><td><a name="VIR_ERR_INVALID_MAC" id="VIR_ERR_INVALID_MAC">VIR_ERR_INVALID_MAC</a></td><td> = </td><td>44</td><td> : invalid MAC address</td></tr><tr><td><a name="VIR_ERR_AUTH_FAILED" id="VIR_ERR_AUTH_FAILED">VIR_ERR_AUTH_FAILED</a></td><td> = </td><td>45</t! d><td> : authentication failed</td></tr><tr><td><a name="VIR_ERR_INVALID_STORAGE_POOL" id="VIR_ERR_INVALID_STORAGE_POOL">VIR_ERR_INVALID_STORAGE_POOL</a></td><td> = </td><td>46</td><td> : invalid storage pool object</td></tr><tr><td><a name="VIR_ERR_INVALID_STORAGE_VOL" id="VIR_ERR_INVALID_STORAGE_VOL">VIR_ERR_INVALID_STORAGE_VOL</a></td><td> = </td><td>47</td><td> : invalid storage vol object</td></tr><tr><td><a name="VIR_WAR_NO_STORAGE" id="VIR_WAR_NO_STORAGE">VIR_WAR_NO_STORAGE</a></td><td> = </td><td>48</td><td> : failed to start storage</td></tr><tr><td><a name="VIR_ERR_NO_STORAGE_POOL" id="VIR_ERR_NO_STORAGE_POOL">VIR_ERR_NO_STORAGE_POOL</a></td><td> = </td><td>49</td><td> : storage pool not found</td></tr><tr><td><a name="VIR_ERR_NO_STORAGE_VOL" id="VIR_ERR_NO_STORAGE_VOL">VIR_ERR_NO_STORAGE_VOL</a></td><td> = </td><td>50</td><td> : storage pool not found</td></tr><tr><td><a name="VIR_WAR_NO_NODE" id="VIR_WAR_NO_NODE">VIR_WAR_NO_NODE</a></td><td> = </td><td>51</td><t! d> : failed to start node driver</td></tr><tr><td><a name="VIR_ERR_INV ALID_NODE_DEVICE" id="VIR_ERR_INVALID_NODE_DEVICE">VIR_ERR_INVALID_NODE_DEVICE</a></td><td> = </td><td>52</td><td> : invalid node device object</td></tr><tr><td><a name="VIR_ERR_NO_NODE_DEVICE" id="VIR_ERR_NO_NODE_DEVICE">VIR_ERR_NO_NODE_DEVICE</a></td><td> = </td><td>53</td><td> : node device not found</td></tr><tr><td><a name="VIR_ERR_NO_SECURITY_MODEL" id="VIR_ERR_NO_SECURITY_MODEL">VIR_ERR_NO_SECURITY_MODEL</a></td><td> = </td><td>54</td><td> : security model not found</td></tr><tr><td><a name="VIR_ERR_OPERATION_INVALID" id="VIR_ERR_OPERATION_INVALID">VIR_ERR_OPERATION_INVALID</a></td><td> = </td><td>55</td><td> : operation is not applicable at this time</td></tr><tr><td><a name="VIR_WAR_NO_INTERFACE" id="VIR_WAR_NO_INTERFACE">VIR_WAR_NO_INTERFACE</a></td><td> = </td><td>56</td><td> : failed to start interface driver</td></tr><tr><td><a name="VIR_ERR_NO_INTERFACE" id="VIR_ERR_NO_INTERFACE">VIR_ERR_NO_INTERFACE</a></td><td> = </td><td>57</td><td> : interface driver not ru! nning</td></tr><tr><td><a name="VIR_ERR_INVALID_INTERFACE" id="VIR_ERR_INVALID_INTERFACE">VIR_ERR_INVALID_INTERFACE</a></td><td> = </td><td>58</td><td> : invalid interface object</td></tr><tr><td><a name="VIR_ERR_MULTIPLE_INTERFACES" id="VIR_ERR_MULTIPLE_INTERFACES">VIR_ERR_MULTIPLE_INTERFACES</a></td><td> = </td><td>59</td><td> : more than one matching interface found</td></tr></table><pre>} +</pre><table><tr><td><a name="VIR_ERR_OK" id="VIR_ERR_OK">VIR_ERR_OK</a></td><td> = </td><td>0</td></tr><tr><td><a name="VIR_ERR_INTERNAL_ERROR" id="VIR_ERR_INTERNAL_ERROR">VIR_ERR_INTERNAL_ERROR</a></td><td> = </td><td>1</td><td> : internal error</td></tr><tr><td><a name="VIR_ERR_NO_MEMORY" id="VIR_ERR_NO_MEMORY">VIR_ERR_NO_MEMORY</a></td><td> = </td><td>2</td><td> : memory allocation failure</td></tr><tr><td><a name="VIR_ERR_NO_SUPPORT" id="VIR_ERR_NO_SUPPORT">VIR_ERR_NO_SUPPORT</a></td><td> = </td><td>3</td><td> : no support for this function</td></tr><tr><td><a name="VIR_ERR_UNKNOWN_HOST" id="VIR_ERR_UNKNOWN_HOST">VIR_ERR_UNKNOWN_HOST</a></td><td> = </td><td>4</td><td> : could not resolve hostname</td></tr><tr><td><a name="VIR_ERR_NO_CONNECT" id="VIR_ERR_NO_CONNECT">VIR_ERR_NO_CONNECT</a></td><td> = </td><td>5</td><td> : can't connect to hypervisor</td></tr><tr><td><a name="VIR_ERR_INVALID_CONN" id="VIR_ERR_INVALID_CONN">VIR_ERR_INVALID_CONN</a></td><td> = </td><td>6</t! d><td> : invalid connection object</td></tr><tr><td><a name="VIR_ERR_INVALID_DOMAIN" id="VIR_ERR_INVALID_DOMAIN">VIR_ERR_INVALID_DOMAIN</a></td><td> = </td><td>7</td><td> : invalid domain object</td></tr><tr><td><a name="VIR_ERR_INVALID_ARG" id="VIR_ERR_INVALID_ARG">VIR_ERR_INVALID_ARG</a></td><td> = </td><td>8</td><td> : invalid function argument</td></tr><tr><td><a name="VIR_ERR_OPERATION_FAILED" id="VIR_ERR_OPERATION_FAILED">VIR_ERR_OPERATION_FAILED</a></td><td> = </td><td>9</td><td> : a command to hypervisor failed</td></tr><tr><td><a name="VIR_ERR_GET_FAILED" id="VIR_ERR_GET_FAILED">VIR_ERR_GET_FAILED</a></td><td> = </td><td>10</td><td> : a HTTP GET command to failed</td></tr><tr><td><a name="VIR_ERR_POST_FAILED" id="VIR_ERR_POST_FAILED">VIR_ERR_POST_FAILED</a></td><td> = </td><td>11</td><td> : a HTTP POST command to failed</td></tr><tr><td><a name="VIR_ERR_HTTP_ERROR" id="VIR_ERR_HTTP_ERROR">VIR_ERR_HTTP_ERROR</a></td><td> = </td><td>12</td><td> : unexpected HTTP erro! r code</td></tr><tr><td><a name="VIR_ERR_SEXPR_SERIAL" id="VIR_ERR_SEX PR_SERIAL">VIR_ERR_SEXPR_SERIAL</a></td><td> = </td><td>13</td><td> : failure to serialize an S-Expr</td></tr><tr><td><a name="VIR_ERR_NO_XEN" id="VIR_ERR_NO_XEN">VIR_ERR_NO_XEN</a></td><td> = </td><td>14</td><td> : could not open Xen hypervisor control</td></tr><tr><td><a name="VIR_ERR_XEN_CALL" id="VIR_ERR_XEN_CALL">VIR_ERR_XEN_CALL</a></td><td> = </td><td>15</td><td> : failure doing an hypervisor call</td></tr><tr><td><a name="VIR_ERR_OS_TYPE" id="VIR_ERR_OS_TYPE">VIR_ERR_OS_TYPE</a></td><td> = </td><td>16</td><td> : unknown OS type</td></tr><tr><td><a name="VIR_ERR_NO_KERNEL" id="VIR_ERR_NO_KERNEL">VIR_ERR_NO_KERNEL</a></td><td> = </td><td>17</td><td> : missing kernel information</td></tr><tr><td><a name="VIR_ERR_NO_ROOT" id="VIR_ERR_NO_ROOT">VIR_ERR_NO_ROOT</a></td><td> = </td><td>18</td><td> : missing root device information</td></tr><tr><td><a name="VIR_ERR_NO_SOURCE" id="VIR_ERR_NO_SOURCE">VIR_ERR_NO_SOURCE</a></td><td> = </td><td>19</td><td> : missing source device ! information</td></tr><tr><td><a name="VIR_ERR_NO_TARGET" id="VIR_ERR_NO_TARGET">VIR_ERR_NO_TARGET</a></td><td> = </td><td>20</td><td> : missing target device information</td></tr><tr><td><a name="VIR_ERR_NO_NAME" id="VIR_ERR_NO_NAME">VIR_ERR_NO_NAME</a></td><td> = </td><td>21</td><td> : missing domain name information</td></tr><tr><td><a name="VIR_ERR_NO_OS" id="VIR_ERR_NO_OS">VIR_ERR_NO_OS</a></td><td> = </td><td>22</td><td> : missing domain OS information</td></tr><tr><td><a name="VIR_ERR_NO_DEVICE" id="VIR_ERR_NO_DEVICE">VIR_ERR_NO_DEVICE</a></td><td> = </td><td>23</td><td> : missing domain devices information</td></tr><tr><td><a name="VIR_ERR_NO_XENSTORE" id="VIR_ERR_NO_XENSTORE">VIR_ERR_NO_XENSTORE</a></td><td> = </td><td>24</td><td> : could not open Xen Store control</td></tr><tr><td><a name="VIR_ERR_DRIVER_FULL" id="VIR_ERR_DRIVER_FULL">VIR_ERR_DRIVER_FULL</a></td><td> = </td><td>25</td><td> : too many drivers registered</td></tr><tr><td><a name="VIR_ERR_CALL_FAILED"! id="VIR_ERR_CALL_FAILED">VIR_ERR_CALL_FAILED</a></td><td> = </td><td> 26</td><td> : not supported by the drivers (DEPRECATED)</td></tr><tr><td><a name="VIR_ERR_XML_ERROR" id="VIR_ERR_XML_ERROR">VIR_ERR_XML_ERROR</a></td><td> = </td><td>27</td><td> : an XML description is not well formed or broken</td></tr><tr><td><a name="VIR_ERR_DOM_EXIST" id="VIR_ERR_DOM_EXIST">VIR_ERR_DOM_EXIST</a></td><td> = </td><td>28</td><td> : the domain already exist</td></tr><tr><td><a name="VIR_ERR_OPERATION_DENIED" id="VIR_ERR_OPERATION_DENIED">VIR_ERR_OPERATION_DENIED</a></td><td> = </td><td>29</td><td> : operation forbidden on read-only connections</td></tr><tr><td><a name="VIR_ERR_OPEN_FAILED" id="VIR_ERR_OPEN_FAILED">VIR_ERR_OPEN_FAILED</a></td><td> = </td><td>30</td><td> : failed to open a conf file</td></tr><tr><td><a name="VIR_ERR_READ_FAILED" id="VIR_ERR_READ_FAILED">VIR_ERR_READ_FAILED</a></td><td> = </td><td>31</td><td> : failed to read a conf file</td></tr><tr><td><a name="VIR_ERR_PARSE_FAILED" id="VIR_ERR_PARSE_FAILED">VIR_ERR_PARSE_FAILED</a></td><td> ! = </td><td>32</td><td> : failed to parse a conf file</td></tr><tr><td><a name="VIR_ERR_CONF_SYNTAX" id="VIR_ERR_CONF_SYNTAX">VIR_ERR_CONF_SYNTAX</a></td><td> = </td><td>33</td><td> : failed to parse the syntax of a conf file</td></tr><tr><td><a name="VIR_ERR_WRITE_FAILED" id="VIR_ERR_WRITE_FAILED">VIR_ERR_WRITE_FAILED</a></td><td> = </td><td>34</td><td> : failed to write a conf file</td></tr><tr><td><a name="VIR_ERR_XML_DETAIL" id="VIR_ERR_XML_DETAIL">VIR_ERR_XML_DETAIL</a></td><td> = </td><td>35</td><td> : detail of an XML error</td></tr><tr><td><a name="VIR_ERR_INVALID_NETWORK" id="VIR_ERR_INVALID_NETWORK">VIR_ERR_INVALID_NETWORK</a></td><td> = </td><td>36</td><td> : invalid network object</td></tr><tr><td><a name="VIR_ERR_NETWORK_EXIST" id="VIR_ERR_NETWORK_EXIST">VIR_ERR_NETWORK_EXIST</a></td><td> = </td><td>37</td><td> : the network already exist</td></tr><tr><td><a name="VIR_ERR_SYSTEM_ERROR" id="VIR_ERR_SYSTEM_ERROR">VIR_ERR_SYSTEM_ERROR</a></td><td> = </td><td>38</td! ><td> : general system call failure</td></tr><tr><td><a name="VIR_ERR_ RPC" id="VIR_ERR_RPC">VIR_ERR_RPC</a></td><td> = </td><td>39</td><td> : some sort of RPC error</td></tr><tr><td><a name="VIR_ERR_GNUTLS_ERROR" id="VIR_ERR_GNUTLS_ERROR">VIR_ERR_GNUTLS_ERROR</a></td><td> = </td><td>40</td><td> : error from a GNUTLS call</td></tr><tr><td><a name="VIR_WAR_NO_NETWORK" id="VIR_WAR_NO_NETWORK">VIR_WAR_NO_NETWORK</a></td><td> = </td><td>41</td><td> : failed to start network</td></tr><tr><td><a name="VIR_ERR_NO_DOMAIN" id="VIR_ERR_NO_DOMAIN">VIR_ERR_NO_DOMAIN</a></td><td> = </td><td>42</td><td> : domain not found or unexpectedly disappeared</td></tr><tr><td><a name="VIR_ERR_NO_NETWORK" id="VIR_ERR_NO_NETWORK">VIR_ERR_NO_NETWORK</a></td><td> = </td><td>43</td><td> : network not found</td></tr><tr><td><a name="VIR_ERR_INVALID_MAC" id="VIR_ERR_INVALID_MAC">VIR_ERR_INVALID_MAC</a></td><td> = </td><td>44</td><td> : invalid MAC address</td></tr><tr><td><a name="VIR_ERR_AUTH_FAILED" id="VIR_ERR_AUTH_FAILED">VIR_ERR_AUTH_FAILED</a></td><td> = </td><td>45</t! d><td> : authentication failed</td></tr><tr><td><a name="VIR_ERR_INVALID_STORAGE_POOL" id="VIR_ERR_INVALID_STORAGE_POOL">VIR_ERR_INVALID_STORAGE_POOL</a></td><td> = </td><td>46</td><td> : invalid storage pool object</td></tr><tr><td><a name="VIR_ERR_INVALID_STORAGE_VOL" id="VIR_ERR_INVALID_STORAGE_VOL">VIR_ERR_INVALID_STORAGE_VOL</a></td><td> = </td><td>47</td><td> : invalid storage vol object</td></tr><tr><td><a name="VIR_WAR_NO_STORAGE" id="VIR_WAR_NO_STORAGE">VIR_WAR_NO_STORAGE</a></td><td> = </td><td>48</td><td> : failed to start storage</td></tr><tr><td><a name="VIR_ERR_NO_STORAGE_POOL" id="VIR_ERR_NO_STORAGE_POOL">VIR_ERR_NO_STORAGE_POOL</a></td><td> = </td><td>49</td><td> : storage pool not found</td></tr><tr><td><a name="VIR_ERR_NO_STORAGE_VOL" id="VIR_ERR_NO_STORAGE_VOL">VIR_ERR_NO_STORAGE_VOL</a></td><td> = </td><td>50</td><td> : storage pool not found</td></tr><tr><td><a name="VIR_WAR_NO_NODE" id="VIR_WAR_NO_NODE">VIR_WAR_NO_NODE</a></td><td> = </td><td>51</td><t! d> : failed to start node driver</td></tr><tr><td><a name="VIR_ERR_INV ALID_NODE_DEVICE" id="VIR_ERR_INVALID_NODE_DEVICE">VIR_ERR_INVALID_NODE_DEVICE</a></td><td> = </td><td>52</td><td> : invalid node device object</td></tr><tr><td><a name="VIR_ERR_NO_NODE_DEVICE" id="VIR_ERR_NO_NODE_DEVICE">VIR_ERR_NO_NODE_DEVICE</a></td><td> = </td><td>53</td><td> : node device not found</td></tr><tr><td><a name="VIR_ERR_NO_SECURITY_MODEL" id="VIR_ERR_NO_SECURITY_MODEL">VIR_ERR_NO_SECURITY_MODEL</a></td><td> = </td><td>54</td><td> : security model not found</td></tr><tr><td><a name="VIR_ERR_OPERATION_INVALID" id="VIR_ERR_OPERATION_INVALID">VIR_ERR_OPERATION_INVALID</a></td><td> = </td><td>55</td><td> : operation is not applicable at this time</td></tr><tr><td><a name="VIR_WAR_NO_INTERFACE" id="VIR_WAR_NO_INTERFACE">VIR_WAR_NO_INTERFACE</a></td><td> = </td><td>56</td><td> : failed to start interface driver</td></tr><tr><td><a name="VIR_ERR_NO_INTERFACE" id="VIR_ERR_NO_INTERFACE">VIR_ERR_NO_INTERFACE</a></td><td> = </td><td>57</td><td> : interface driver not ru! nning</td></tr><tr><td><a name="VIR_ERR_INVALID_INTERFACE" id="VIR_ERR_INVALID_INTERFACE">VIR_ERR_INVALID_INTERFACE</a></td><td> = </td><td>58</td><td> : invalid interface object</td></tr><tr><td><a name="VIR_ERR_MULTIPLE_INTERFACES" id="VIR_ERR_MULTIPLE_INTERFACES">VIR_ERR_MULTIPLE_INTERFACES</a></td><td> = </td><td>59</td><td> : more than one matching interface found</td></tr><tr><td><a name="VIR_WAR_NO_SECRET" id="VIR_WAR_NO_SECRET">VIR_WAR_NO_SECRET</a></td><td> = </td><td>60</td><td> : failed to start secret storage</td></tr><tr><td><a name="VIR_ERR_INVALID_SECRET" id="VIR_ERR_INVALID_SECRET">VIR_ERR_INVALID_SECRET</a></td><td> = </td><td>61</td><td> : invalid secret</td></tr><tr><td><a name="VIR_ERR_NO_SECRET" id="VIR_ERR_NO_SECRET">VIR_ERR_NO_SECRET</a></td><td> = </td><td>62</td><td> : secret not found</td></tr></table><pre>} </pre></div><h3><a name="functions" id="functions">Functions</a></h3><h3><a name="virConnCopyLastError" id="virConnCopyLastError"><code>virConnCopyLastError</code></a></h3><pre class="programlisting">int virConnCopyLastError (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br /> <a href="libvirt-virterror.html#virErrorPtr">virErrorPtr</a> to)<br /> </pre><p>Copy the content of the last error caught on that connection This method is not protected against access from multiple threads. In a multi-threaded application, always use the global virGetLastError() API which is backed by thread local storage. If the connection object was discovered to be invalid by an API call, then the error will be reported against the global error object. Since 0.6.0, all errors reported in the per-connection object are also duplicated in the global error object. As such an application can always use virGetLastError(). This method remains for backwards compatability. One will need to free the result with virResetError()</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to the hypervisor connection</td></tr><tr><td><span class="term"><i><tt>to</tt></i>:</span></td><td>target to receive the copy</td></tr><tr><td><span class="term"><i><tt>Returns</tt>! </i>:</span></td><td>0 if no error was found and the error code otherwise and -1 in case of parameter error.</td></tr></tbody></table></div><h3><a name="virConnGetLastError" id="virConnGetLastError"><code>virConnGetLastError</code></a></h3><pre class="programlisting"><a href="libvirt-virterror.html#virErrorPtr">virErrorPtr</a> virConnGetLastError (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn)<br /> </pre><p>Provide a pointer to the last error caught on that connection This method is not protected against access from multiple threads. In a multi-threaded application, always use the global virGetLastError() API which is backed by thread local storage. If the connection object was discovered to be invalid by an API call, then the error will be reported against the global error object. Since 0.6.0, all errors reported in the per-connection object are also duplicated in the global error object. As such an application can always use virGetLastError(). This method remains for backwards compatability.</p><div class="variablelist"><table border="0"><col align="left" /><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to the hypervisor connection</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>a pointer to the last error or NULL if none occurred.</td></tr></tbody></table></div><h3><a name="virConnResetLastError" id="virCo! nnResetLastError"><code>virConnResetLastError</code></a></h3><pre class="programlisting">void virConnResetLastError (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn)<br /> diff --git a/docs/libvirt-api.xml b/docs/libvirt-api.xml index 0d244ea..0dca74f 100644 --- a/docs/libvirt-api.xml +++ b/docs/libvirt-api.xml @@ -97,6 +97,7 @@ <exports symbol='virDomainEventResumedDetailType' type='typedef'/> <exports symbol='virDomainBlockStatsPtr' type='typedef'/> <exports symbol='virConnect' type='typedef'/> + <exports symbol='virSecretPtr' type='typedef'/> <exports symbol='virDomainEventStartedDetailType' type='typedef'/> <exports symbol='virDomainInfo' type='typedef'/> <exports symbol='virStoragePoolDeleteFlags' type='typedef'/> @@ -105,6 +106,7 @@ <exports symbol='virDomainEventType' type='typedef'/> <exports symbol='virDomainInterfaceStatsStruct' type='typedef'/> <exports symbol='virStoragePoolInfo' type='typedef'/> + <exports symbol='virSecret' type='typedef'/> <exports symbol='virDomainState' type='typedef'/> <exports symbol='virDomain' type='typedef'/> <exports symbol='virDomainInterfaceStatsPtr' type='typedef'/> @@ -164,16 +166,18 @@ <exports symbol='_virSchedParameter' type='struct'/> <exports symbol='virConnectAuthPtrDefault' type='variable'/> <exports symbol='virStoragePoolGetXMLDesc' type='function'/> + <exports symbol='virSecretGetUUIDString' type='function'/> <exports symbol='virStorageVolGetKey' type='function'/> <exports symbol='virEventUpdateTimeoutFunc' type='function'/> - <exports symbol='virConnectClose' type='function'/> + <exports symbol='virDomainUndefine' type='function'/> <exports symbol='virDomainDefineXML' type='function'/> <exports symbol='virDomainShutdown' type='function'/> - <exports symbol='virConnectListStoragePools' type='function'/> + <exports symbol='virConnectListDefinedInterfaces' type='function'/> <exports symbol='virGetVersion' type='function'/> <exports symbol='virNodeGetCellsFreeMemory' type='function'/> <exports symbol='virInitialize' type='function'/> <exports symbol='virNodeDeviceGetName' type='function'/> + <exports symbol='virConnectNumOfSecrets' type='function'/> <exports symbol='virStoragePoolSetAutostart' type='function'/> <exports symbol='virConnectDomainXMLFromNative' type='function'/> <exports symbol='virNodeDeviceDettach' type='function'/> @@ -182,7 +186,7 @@ <exports symbol='virDomainGetSchedulerParameters' type='function'/> <exports symbol='virDomainLookupByUUIDString' type='function'/> <exports symbol='virConnectNumOfDefinedNetworks' type='function'/> - <exports symbol='virConnectListDefinedInterfaces' type='function'/> + <exports symbol='virConnectListStoragePools' type='function'/> <exports symbol='virNetworkGetUUID' type='function'/> <exports symbol='virInterfaceGetXMLDesc' type='function'/> <exports symbol='virStoragePoolGetConnect' type='function'/> @@ -206,6 +210,7 @@ <exports symbol='virDomainDestroy' type='function'/> <exports symbol='virConnectNumOfNetworks' type='function'/> <exports symbol='virStoragePoolLookupByUUIDString' type='function'/> + <exports symbol='virSecretGetConnect' type='function'/> <exports symbol='virInterfaceCreate' type='function'/> <exports symbol='virDomainGetXMLDesc' type='function'/> <exports symbol='virStoragePoolGetUUID' type='function'/> @@ -232,6 +237,7 @@ <exports symbol='virStoragePoolCreate' type='function'/> <exports symbol='virNodeGetInfo' type='function'/> <exports symbol='virNetworkSetAutostart' type='function'/> + <exports symbol='virSecretLookupByUUIDString' type='function'/> <exports symbol='virDomainGetMaxMemory' type='function'/> <exports symbol='virStoragePoolFree' type='function'/> <exports symbol='virConnectNumOfDefinedInterfaces' type='function'/> @@ -241,7 +247,7 @@ <exports symbol='virDomainBlockStats' type='function'/> <exports symbol='virConnectOpenAuth' type='function'/> <exports symbol='virStoragePoolDelete' type='function'/> - <exports symbol='virEventRemoveHandleFunc' type='function'/> + <exports symbol='virDomainResume' type='function'/> <exports symbol='virStorageVolGetName' type='function'/> <exports symbol='virStoragePoolGetAutostart' type='function'/> <exports symbol='virDomainGetAutostart' type='function'/> @@ -254,10 +260,12 @@ <exports symbol='virConnectNumOfStoragePools' type='function'/> <exports symbol='virInterfaceGetConnect' type='function'/> <exports symbol='virNetworkGetName' type='function'/> + <exports symbol='virSecretGetXMLDesc' type='function'/> <exports symbol='virConnectListDefinedDomains' type='function'/> <exports symbol='virConnectGetCapabilities' type='function'/> <exports symbol='virDomainLookupByName' type='function'/> <exports symbol='virConnectFindStoragePoolSources' type='function'/> + <exports symbol='virStorageVolFree' type='function'/> <exports symbol='virDomainPinVcpu' type='function'/> <exports symbol='virNodeGetSecurityModel' type='function'/> <exports symbol='virDomainRestore' type='function'/> @@ -267,7 +275,7 @@ <exports symbol='virConnectDomainEventCallback' type='function'/> <exports symbol='virDomainLookupByID' type='function'/> <exports symbol='virStorageVolDelete' type='function'/> - <exports symbol='virStorageVolFree' type='function'/> + <exports symbol='virSecretUndefine' type='function'/> <exports symbol='virConnectListInterfaces' type='function'/> <exports symbol='virDomainMemoryPeek' type='function'/> <exports symbol='virNetworkLookupByUUID' type='function'/> @@ -280,14 +288,14 @@ <exports symbol='virDomainGetVcpus' type='function'/> <exports symbol='virNodeDeviceLookupByName' type='function'/> <exports symbol='virStoragePoolGetInfo' type='function'/> - <exports symbol='virDomainResume' type='function'/> + <exports symbol='virEventRemoveHandleFunc' type='function'/> <exports symbol='virInterfaceRef' type='function'/> <exports symbol='virInterfaceGetMACString' type='function'/> <exports symbol='virConnectNumOfDomains' type='function'/> <exports symbol='virStoragePoolRefresh' type='function'/> <exports symbol='virConnectNumOfDefinedDomains' type='function'/> <exports symbol='virStorageVolCreateXMLFrom' type='function'/> - <exports symbol='virDomainUndefine' type='function'/> + <exports symbol='virConnectClose' type='function'/> <exports symbol='virDomainReboot' type='function'/> <exports symbol='virNetworkGetUUIDString' type='function'/> <exports symbol='virNetworkLookupByName' type='function'/> @@ -304,6 +312,7 @@ <exports symbol='virDomainAttachDevice' type='function'/> <exports symbol='virConnectGetURI' type='function'/> <exports symbol='virConnectOpenReadOnly' type='function'/> + <exports symbol='virSecretDefineXML' type='function'/> <exports symbol='virNetworkFree' type='function'/> <exports symbol='virStoragePoolLookupByUUID' type='function'/> <exports symbol='virEventAddHandleFunc' type='function'/> @@ -316,6 +325,7 @@ <exports symbol='virNetworkGetConnect' type='function'/> <exports symbol='virNodeGetFreeMemory' type='function'/> <exports symbol='virInterfaceDestroy' type='function'/> + <exports symbol='virSecretSetValue' type='function'/> <exports symbol='virStorageVolGetConnect' type='function'/> <exports symbol='virNodeNumOfDevices' type='function'/> <exports symbol='virStoragePoolDestroy' type='function'/> @@ -327,6 +337,7 @@ <exports symbol='virDomainGetUUIDString' type='function'/> <exports symbol='virDomainGetConnect' type='function'/> <exports symbol='virConnectNumOfDefinedStoragePools' type='function'/> + <exports symbol='virSecretFree' type='function'/> <exports symbol='virNodeListDevices' type='function'/> <exports symbol='virNodeDeviceGetParent' type='function'/> <exports symbol='virConnectOpen' type='function'/> @@ -335,13 +346,16 @@ <exports symbol='virInterfaceUndefine' type='function'/> <exports symbol='virDomainSetVcpus' type='function'/> <exports symbol='virDomainRef' type='function'/> + <exports symbol='virConnectListSecrets' type='function'/> <exports symbol='virConnectNumOfInterfaces' type='function'/> <exports symbol='virDomainGetID' type='function'/> + <exports symbol='virSecretRef' type='function'/> <exports symbol='virDomainBlockPeek' type='function'/> <exports symbol='virEventAddTimeoutFunc' type='function'/> <exports symbol='virInterfaceLookupByName' type='function'/> <exports symbol='virDomainInterfaceStats' type='function'/> <exports symbol='virConnectListNetworks' type='function'/> + <exports symbol='virSecretGetValue' type='function'/> <exports symbol='virStorageVolLookupByKey' type='function'/> </file> <file name='virterror'> @@ -355,12 +369,14 @@ <exports symbol='VIR_ERR_NO_MEMORY' type='enum'/> <exports symbol='VIR_WAR_NO_NODE' type='enum'/> <exports symbol='VIR_ERR_NO_STORAGE_VOL' type='enum'/> + <exports symbol='VIR_FROM_XML' type='enum'/> <exports symbol='VIR_FROM_CONF' type='enum'/> <exports symbol='VIR_ERR_INVALID_NETWORK' type='enum'/> <exports symbol='VIR_ERR_PARSE_FAILED' type='enum'/> <exports symbol='VIR_ERR_POST_FAILED' type='enum'/> <exports symbol='VIR_ERR_INVALID_CONN' type='enum'/> <exports symbol='VIR_ERR_GET_FAILED' type='enum'/> + <exports symbol='VIR_FROM_XEN' type='enum'/> <exports symbol='VIR_ERR_NO_SOURCE' type='enum'/> <exports symbol='VIR_ERR_NETWORK_EXIST' type='enum'/> <exports symbol='VIR_ERR_NONE' type='enum'/> @@ -383,6 +399,7 @@ <exports symbol='VIR_FROM_STATS_LINUX' type='enum'/> <exports symbol='VIR_FROM_OPENVZ' type='enum'/> <exports symbol='VIR_ERR_OS_TYPE' type='enum'/> + <exports symbol='VIR_WAR_NO_SECRET' type='enum'/> <exports symbol='VIR_WAR_NO_NETWORK' type='enum'/> <exports symbol='VIR_FROM_UML' type='enum'/> <exports symbol='VIR_ERR_NO_NAME' type='enum'/> @@ -408,21 +425,22 @@ <exports symbol='VIR_ERR_GNUTLS_ERROR' type='enum'/> <exports symbol='VIR_ERR_XML_ERROR' type='enum'/> <exports symbol='VIR_ERR_OK' type='enum'/> - <exports symbol='VIR_ERR_INVALID_INTERFACE' type='enum'/> <exports symbol='VIR_FROM_STORAGE' type='enum'/> <exports symbol='VIR_FROM_PROXY' type='enum'/> <exports symbol='VIR_ERR_DRIVER_FULL' type='enum'/> <exports symbol='VIR_FROM_DOMAIN' type='enum'/> - <exports symbol='VIR_FROM_XML' type='enum'/> + <exports symbol='VIR_ERR_INVALID_SECRET' type='enum'/> <exports symbol='VIR_ERR_OPERATION_DENIED' type='enum'/> <exports symbol='VIR_ERR_INVALID_STORAGE_POOL' type='enum'/> + <exports symbol='VIR_FROM_SECRET' type='enum'/> <exports symbol='VIR_ERR_NO_DOMAIN' type='enum'/> - <exports symbol='VIR_FROM_XEN' type='enum'/> + <exports symbol='VIR_ERR_INVALID_INTERFACE' type='enum'/> <exports symbol='VIR_ERR_RPC' type='enum'/> <exports symbol='VIR_ERR_WARNING' type='enum'/> <exports symbol='VIR_ERR_INVALID_ARG' type='enum'/> <exports symbol='VIR_ERR_CALL_FAILED' type='enum'/> <exports symbol='VIR_ERR_ERROR' type='enum'/> + <exports symbol='VIR_ERR_NO_SECRET' type='enum'/> <exports symbol='VIR_WAR_NO_INTERFACE' type='enum'/> <exports symbol='VIR_ERR_DOM_EXIST' type='enum'/> <exports symbol='VIR_FROM_LXC' type='enum'/> @@ -587,9 +605,10 @@ <enum name='VIR_ERR_INVALID_MAC' file='virterror' value='44' type='virErrorNumber' info='invalid MAC address'/> <enum name='VIR_ERR_INVALID_NETWORK' file='virterror' value='36' type='virErrorNumber' info='invalid network object'/> <enum name='VIR_ERR_INVALID_NODE_DEVICE' file='virterror' value='52' type='virErrorNumber' info='invalid node device object'/> + <enum name='VIR_ERR_INVALID_SECRET' file='virterror' value='61' type='virErrorNumber' info='invalid secret'/> <enum name='VIR_ERR_INVALID_STORAGE_POOL' file='virterror' value='46' type='virErrorNumber' info='invalid storage pool object'/> <enum name='VIR_ERR_INVALID_STORAGE_VOL' file='virterror' value='47' type='virErrorNumber' info='invalid storage vol object'/> - <enum name='VIR_ERR_MULTIPLE_INTERFACES' file='virterror' value='59' type='virErrorNumber' info=' more than one matching interface found'/> + <enum name='VIR_ERR_MULTIPLE_INTERFACES' file='virterror' value='59' type='virErrorNumber' info='more than one matching interface found'/> <enum name='VIR_ERR_NETWORK_EXIST' file='virterror' value='37' type='virErrorNumber' info='the network already exist'/> <enum name='VIR_ERR_NONE' file='virterror' value='0' type='virErrorLevel'/> <enum name='VIR_ERR_NO_CONNECT' file='virterror' value='5' type='virErrorNumber' info='can't connect to hypervisor'/> @@ -603,6 +622,7 @@ <enum name='VIR_ERR_NO_NODE_DEVICE' file='virterror' value='53' type='virErrorNumber' info='node device not found'/> <enum name='VIR_ERR_NO_OS' file='virterror' value='22' type='virErrorNumber' info='missing domain OS information'/> <enum name='VIR_ERR_NO_ROOT' file='virterror' value='18' type='virErrorNumber' info='missing root device information'/> + <enum name='VIR_ERR_NO_SECRET' file='virterror' value='62' type='virErrorNumber' info=' secret not found'/> <enum name='VIR_ERR_NO_SECURITY_MODEL' file='virterror' value='54' type='virErrorNumber' info='security model not found'/> <enum name='VIR_ERR_NO_SOURCE' file='virterror' value='19' type='virErrorNumber' info='missing source device information'/> <enum name='VIR_ERR_NO_STORAGE_POOL' file='virterror' value='49' type='virErrorNumber' info='storage pool not found'/> @@ -645,11 +665,12 @@ <enum name='VIR_FROM_NONE' file='virterror' value='0' type='virErrorDomain'/> <enum name='VIR_FROM_ONE' file='virterror' value='27' type='virErrorDomain' info='Error from OpenNebula driver'/> <enum name='VIR_FROM_OPENVZ' file='virterror' value='14' type='virErrorDomain' info='Error from OpenVZ driver'/> - <enum name='VIR_FROM_PHYP' file='virterror' value='29' type='virErrorDomain' info=' Error from IBM power hypervisor'/> + <enum name='VIR_FROM_PHYP' file='virterror' value='29' type='virErrorDomain' info='Error from IBM power hypervisor'/> <enum name='VIR_FROM_PROXY' file='virterror' value='8' type='virErrorDomain' info='Error in the proxy code'/> <enum name='VIR_FROM_QEMU' file='virterror' value='10' type='virErrorDomain' info='Error at the QEMU daemon'/> <enum name='VIR_FROM_REMOTE' file='virterror' value='13' type='virErrorDomain' info='Error from remote driver'/> <enum name='VIR_FROM_RPC' file='virterror' value='7' type='virErrorDomain' info='Error in the XML-RPC code'/> + <enum name='VIR_FROM_SECRET' file='virterror' value='30' type='virErrorDomain' info=' Error from secret storage'/> <enum name='VIR_FROM_SECURITY' file='virterror' value='24' type='virErrorDomain' info='Error from security framework'/> <enum name='VIR_FROM_SEXPR' file='virterror' value='4' type='virErrorDomain' info='Error in the S-Expression code'/> <enum name='VIR_FROM_STATS_LINUX' file='virterror' value='16' type='virErrorDomain' info='Error in the Linux Stats code'/> @@ -685,6 +706,7 @@ <enum name='VIR_WAR_NO_INTERFACE' file='virterror' value='56' type='virErrorNumber' info='failed to start interface driver'/> <enum name='VIR_WAR_NO_NETWORK' file='virterror' value='41' type='virErrorNumber' info='failed to start network'/> <enum name='VIR_WAR_NO_NODE' file='virterror' value='51' type='virErrorNumber' info='failed to start node driver'/> + <enum name='VIR_WAR_NO_SECRET' file='virterror' value='60' type='virErrorNumber' info='failed to start secret storage'/> <enum name='VIR_WAR_NO_STORAGE' file='virterror' value='48' type='virErrorNumber' info='failed to start storage'/> <struct name='virConnect' file='libvirt' type='struct _virConnect'/> <struct name='virConnectAuth' file='libvirt' type='struct _virConnectAuth'> @@ -812,6 +834,8 @@ see note above'/> <info>a virSchedParameterPtr is a pointer to a virSchedParameter structure.</info> </typedef> <typedef name='virSchedParameterType' file='libvirt' type='enum'/> + <struct name='virSecret' file='libvirt' type='struct _virSecret'/> + <typedef name='virSecretPtr' file='libvirt' type='virSecret *'/> <struct name='virSecurityLabel' file='libvirt' type='struct _virSecurityLabel'/> <typedef name='virSecurityLabelPtr' file='libvirt' type='virSecurityLabel *'> <info>a virSecurityLabelPtr is a pointer to a virSecurityLabel.</info> @@ -1018,6 +1042,13 @@ see note above'/> <arg name='names' type='char ** const' info='array to collect the list of names of active networks'/> <arg name='maxnames' type='int' info='size of @names'/> </function> + <function name='virConnectListSecrets' file='libvirt' module='libvirt'> + <info>List UUIDs of defined secrets, store pointers to names in uuids.</info> + <return type='int' info='the number of UUIDs provided in the array, or -1 on failure.'/> + <arg name='conn' type='virConnectPtr' info='virConnect connection'/> + <arg name='uuids' type='char **' info='Pointer to an array to store the UUIDs'/> + <arg name='maxuuids' type='int' info='size of the array.'/> + </function> <function name='virConnectListStoragePools' file='libvirt' module='libvirt'> <info>Provides the list of names of active storage pools upto maxnames. If there are more than maxnames, the remaining names will be silently ignored.</info> <return type='int' info='0 on success, -1 on error'/> @@ -1060,6 +1091,11 @@ see note above'/> <return type='int' info='the number of network found or -1 in case of error'/> <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> </function> + <function name='virConnectNumOfSecrets' file='libvirt' module='libvirt'> + <info>Fetch number of currently defined secrets.</info> + <return type='int' info='the number currently defined secrets.'/> + <arg name='conn' type='virConnectPtr' info='virConnect connection'/> + </function> <function name='virConnectNumOfStoragePools' file='libvirt' module='libvirt'> <info>Provides the number of active storage pools</info> <return type='int' info='the number of pools found, or -1 on error'/> @@ -1776,6 +1812,61 @@ see note above'/> <info>Save the last error into a new error object.</info> <return type='virErrorPtr' info='a pointer to the copied error or NULL if allocation failed. It is the caller's responsibility to free the error with virFreeError().'/> </function> + <function name='virSecretDefineXML' file='libvirt' module='libvirt'> + <info>If XML specifies an UUID, locates the specified secret and replaces all attributes of the secret specified by UUID by attributes specified in xml (any attributes not specified in xml are discarded). Otherwise, creates a new secret with an automatically chosen UUID, and initializes its attributes from xml.</info> + <return type='virSecretPtr' info='a the secret on success, NULL on failure.'/> + <arg name='conn' type='virConnectPtr' info='virConnect connection'/> + <arg name='xml' type='const char *' info='XML describing the secret.'/> + </function> + <function name='virSecretFree' file='libvirt' module='libvirt'> + <info>Release the secret handle. The underlying secret continues to exist.</info> + <return type='int' info='0 on success, or -1 on error'/> + <arg name='secret' type='virSecretPtr' info='pointer to a secret'/> + </function> + <function name='virSecretGetConnect' file='libvirt' module='libvirt'> + <info>Provides the connection pointer associated with a secret. The reference counter on the connection is not increased by this call. WARNING: When writing libvirt bindings in other languages, do not use this function. Instead, store the connection and the secret object together.</info> + <return type='virConnectPtr' info='the virConnectPtr or NULL in case of failure.'/> + <arg name='secret' type='virSecretPtr' info='A virSecret secret'/> + </function> + <function name='virSecretGetUUIDString' file='libvirt' module='libvirt'> + <info>Fetches the UUID of the secret.</info> + <return type='char *' info='ID of the secret (not necessarily in the UUID format) on success, NULL on failure. The caller must free() the ID.'/> + <arg name='secret' type='virSecretPtr' info='A virSecret secret'/> + </function> + <function name='virSecretGetValue' file='libvirt' module='libvirt'> + <info>Fetches the value of a secret.</info> + <return type='unsigned char *' info='the secret value on success, NULL on failure. The caller must free() the secret value.'/> + <arg name='secret' type='virSecretPtr' info='A virSecret connection'/> + <arg name='value_size' type='size_t *' info='Place for storing size of the secret value'/> + </function> + <function name='virSecretGetXMLDesc' file='libvirt' module='libvirt'> + <info>Fetches an XML document describing attributes of the secret.</info> + <return type='char *' info='the XML document on success, NULL on failure. The caller must free() the XML.'/> + <arg name='secret' type='virSecretPtr' info='A virSecret secret'/> + </function> + <function name='virSecretLookupByUUIDString' file='libvirt' module='libvirt'> + <info>Fetches a secret based on uuid.</info> + <return type='virSecretPtr' info='the secret on success, or NULL on failure.'/> + <arg name='conn' type='virConnectPtr' info='virConnect connection'/> + <arg name='uuid' type='const char *' info='ID of a secret'/> + </function> + <function name='virSecretRef' file='libvirt' module='libvirt'> + <info>Increment the reference count on the secret. For each additional call to this method, there shall be a corresponding call to virSecretFree to release the reference count, once the caller no longer needs the reference to this object. This method is typically useful for applications where multiple threads are using a connection, and it is required that the connection remain open until all threads have finished using it. ie, each new thread using a secret would increment the reference count.</info> + <return type='int' info='0 in case of success, -1 in case of failure.'/> + <arg name='secret' type='virSecretPtr' info='the secret to hold a reference on'/> + </function> + <function name='virSecretSetValue' file='libvirt' module='libvirt'> + <info>Sets the value of a secret.</info> + <return type='int' info='0 on success, -1 on failure.'/> + <arg name='secret' type='virSecretPtr' info='A virSecret secret'/> + <arg name='value' type='const unsigned char *' info='Value of the secret'/> + <arg name='value_size' type='size_t' info='Size of the value'/> + </function> + <function name='virSecretUndefine' file='libvirt' module='libvirt'> + <info>Deletes the specified secret. This does not free the associated virSecretPtr object.</info> + <return type='int' info='0 on success, -1 on failure.'/> + <arg name='secret' type='virSecretPtr' info='A virSecret secret'/> + </function> <function name='virSetErrorFunc' file='virterror' module='virterror'> <info>Set a library global error handling function, if @handler is NULL, it will reset to default printing on stderr. The error raised there are those for which no handler at the connection level could caught.</info> <return type='void'/> diff --git a/docs/libvirt-refs.xml b/docs/libvirt-refs.xml index 0bceb63..6b0e842 100644 --- a/docs/libvirt-refs.xml +++ b/docs/libvirt-refs.xml @@ -71,6 +71,7 @@ <reference name='VIR_ERR_INVALID_MAC' href='html/libvirt-virterror.html#VIR_ERR_INVALID_MAC'/> <reference name='VIR_ERR_INVALID_NETWORK' href='html/libvirt-virterror.html#VIR_ERR_INVALID_NETWORK'/> <reference name='VIR_ERR_INVALID_NODE_DEVICE' href='html/libvirt-virterror.html#VIR_ERR_INVALID_NODE_DEVICE'/> + <reference name='VIR_ERR_INVALID_SECRET' href='html/libvirt-virterror.html#VIR_ERR_INVALID_SECRET'/> <reference name='VIR_ERR_INVALID_STORAGE_POOL' href='html/libvirt-virterror.html#VIR_ERR_INVALID_STORAGE_POOL'/> <reference name='VIR_ERR_INVALID_STORAGE_VOL' href='html/libvirt-virterror.html#VIR_ERR_INVALID_STORAGE_VOL'/> <reference name='VIR_ERR_MULTIPLE_INTERFACES' href='html/libvirt-virterror.html#VIR_ERR_MULTIPLE_INTERFACES'/> @@ -87,6 +88,7 @@ <reference name='VIR_ERR_NO_NODE_DEVICE' href='html/libvirt-virterror.html#VIR_ERR_NO_NODE_DEVICE'/> <reference name='VIR_ERR_NO_OS' href='html/libvirt-virterror.html#VIR_ERR_NO_OS'/> <reference name='VIR_ERR_NO_ROOT' href='html/libvirt-virterror.html#VIR_ERR_NO_ROOT'/> + <reference name='VIR_ERR_NO_SECRET' href='html/libvirt-virterror.html#VIR_ERR_NO_SECRET'/> <reference name='VIR_ERR_NO_SECURITY_MODEL' href='html/libvirt-virterror.html#VIR_ERR_NO_SECURITY_MODEL'/> <reference name='VIR_ERR_NO_SOURCE' href='html/libvirt-virterror.html#VIR_ERR_NO_SOURCE'/> <reference name='VIR_ERR_NO_STORAGE_POOL' href='html/libvirt-virterror.html#VIR_ERR_NO_STORAGE_POOL'/> @@ -134,6 +136,7 @@ <reference name='VIR_FROM_QEMU' href='html/libvirt-virterror.html#VIR_FROM_QEMU'/> <reference name='VIR_FROM_REMOTE' href='html/libvirt-virterror.html#VIR_FROM_REMOTE'/> <reference name='VIR_FROM_RPC' href='html/libvirt-virterror.html#VIR_FROM_RPC'/> + <reference name='VIR_FROM_SECRET' href='html/libvirt-virterror.html#VIR_FROM_SECRET'/> <reference name='VIR_FROM_SECURITY' href='html/libvirt-virterror.html#VIR_FROM_SECURITY'/> <reference name='VIR_FROM_SEXPR' href='html/libvirt-virterror.html#VIR_FROM_SEXPR'/> <reference name='VIR_FROM_STATS_LINUX' href='html/libvirt-virterror.html#VIR_FROM_STATS_LINUX'/> @@ -178,6 +181,7 @@ <reference name='VIR_WAR_NO_INTERFACE' href='html/libvirt-virterror.html#VIR_WAR_NO_INTERFACE'/> <reference name='VIR_WAR_NO_NETWORK' href='html/libvirt-virterror.html#VIR_WAR_NO_NETWORK'/> <reference name='VIR_WAR_NO_NODE' href='html/libvirt-virterror.html#VIR_WAR_NO_NODE'/> + <reference name='VIR_WAR_NO_SECRET' href='html/libvirt-virterror.html#VIR_WAR_NO_SECRET'/> <reference name='VIR_WAR_NO_STORAGE' href='html/libvirt-virterror.html#VIR_WAR_NO_STORAGE'/> <reference name='_virConnectAuth' href='html/libvirt-libvirt.html#_virConnectAuth'/> <reference name='_virConnectCredential' href='html/libvirt-libvirt.html#_virConnectCredential'/> @@ -225,6 +229,7 @@ <reference name='virConnectListDomains' href='html/libvirt-libvirt.html#virConnectListDomains'/> <reference name='virConnectListInterfaces' href='html/libvirt-libvirt.html#virConnectListInterfaces'/> <reference name='virConnectListNetworks' href='html/libvirt-libvirt.html#virConnectListNetworks'/> + <reference name='virConnectListSecrets' href='html/libvirt-libvirt.html#virConnectListSecrets'/> <reference name='virConnectListStoragePools' href='html/libvirt-libvirt.html#virConnectListStoragePools'/> <reference name='virConnectNumOfDefinedDomains' href='html/libvirt-libvirt.html#virConnectNumOfDefinedDomains'/> <reference name='virConnectNumOfDefinedInterfaces' href='html/libvirt-libvirt.html#virConnectNumOfDefinedInterfaces'/> @@ -233,6 +238,7 @@ <reference name='virConnectNumOfDomains' href='html/libvirt-libvirt.html#virConnectNumOfDomains'/> <reference name='virConnectNumOfInterfaces' href='html/libvirt-libvirt.html#virConnectNumOfInterfaces'/> <reference name='virConnectNumOfNetworks' href='html/libvirt-libvirt.html#virConnectNumOfNetworks'/> + <reference name='virConnectNumOfSecrets' href='html/libvirt-libvirt.html#virConnectNumOfSecrets'/> <reference name='virConnectNumOfStoragePools' href='html/libvirt-libvirt.html#virConnectNumOfStoragePools'/> <reference name='virConnectOpen' href='html/libvirt-libvirt.html#virConnectOpen'/> <reference name='virConnectOpenAuth' href='html/libvirt-libvirt.html#virConnectOpenAuth'/> @@ -392,6 +398,18 @@ <reference name='virSchedParameter' href='html/libvirt-libvirt.html#virSchedParameter'/> <reference name='virSchedParameterPtr' href='html/libvirt-libvirt.html#virSchedParameterPtr'/> <reference name='virSchedParameterType' href='html/libvirt-libvirt.html#virSchedParameterType'/> + <reference name='virSecret' href='html/libvirt-libvirt.html#virSecret'/> + <reference name='virSecretDefineXML' href='html/libvirt-libvirt.html#virSecretDefineXML'/> + <reference name='virSecretFree' href='html/libvirt-libvirt.html#virSecretFree'/> + <reference name='virSecretGetConnect' href='html/libvirt-libvirt.html#virSecretGetConnect'/> + <reference name='virSecretGetUUIDString' href='html/libvirt-libvirt.html#virSecretGetUUIDString'/> + <reference name='virSecretGetValue' href='html/libvirt-libvirt.html#virSecretGetValue'/> + <reference name='virSecretGetXMLDesc' href='html/libvirt-libvirt.html#virSecretGetXMLDesc'/> + <reference name='virSecretLookupByUUIDString' href='html/libvirt-libvirt.html#virSecretLookupByUUIDString'/> + <reference name='virSecretPtr' href='html/libvirt-libvirt.html#virSecretPtr'/> + <reference name='virSecretRef' href='html/libvirt-libvirt.html#virSecretRef'/> + <reference name='virSecretSetValue' href='html/libvirt-libvirt.html#virSecretSetValue'/> + <reference name='virSecretUndefine' href='html/libvirt-libvirt.html#virSecretUndefine'/> <reference name='virSecurityLabel' href='html/libvirt-libvirt.html#virSecurityLabel'/> <reference name='virSecurityLabelPtr' href='html/libvirt-libvirt.html#virSecurityLabelPtr'/> <reference name='virSecurityModel' href='html/libvirt-libvirt.html#virSecurityModel'/> @@ -526,6 +544,7 @@ <ref name='VIR_ERR_INVALID_MAC'/> <ref name='VIR_ERR_INVALID_NETWORK'/> <ref name='VIR_ERR_INVALID_NODE_DEVICE'/> + <ref name='VIR_ERR_INVALID_SECRET'/> <ref name='VIR_ERR_INVALID_STORAGE_POOL'/> <ref name='VIR_ERR_INVALID_STORAGE_VOL'/> <ref name='VIR_ERR_MULTIPLE_INTERFACES'/> @@ -542,6 +561,7 @@ <ref name='VIR_ERR_NO_NODE_DEVICE'/> <ref name='VIR_ERR_NO_OS'/> <ref name='VIR_ERR_NO_ROOT'/> + <ref name='VIR_ERR_NO_SECRET'/> <ref name='VIR_ERR_NO_SECURITY_MODEL'/> <ref name='VIR_ERR_NO_SOURCE'/> <ref name='VIR_ERR_NO_STORAGE_POOL'/> @@ -589,6 +609,7 @@ <ref name='VIR_FROM_QEMU'/> <ref name='VIR_FROM_REMOTE'/> <ref name='VIR_FROM_RPC'/> + <ref name='VIR_FROM_SECRET'/> <ref name='VIR_FROM_SECURITY'/> <ref name='VIR_FROM_SEXPR'/> <ref name='VIR_FROM_STATS_LINUX'/> @@ -633,6 +654,7 @@ <ref name='VIR_WAR_NO_INTERFACE'/> <ref name='VIR_WAR_NO_NETWORK'/> <ref name='VIR_WAR_NO_NODE'/> + <ref name='VIR_WAR_NO_SECRET'/> <ref name='VIR_WAR_NO_STORAGE'/> </letter> <letter name='_'> @@ -684,6 +706,7 @@ <ref name='virConnectListDomains'/> <ref name='virConnectListInterfaces'/> <ref name='virConnectListNetworks'/> + <ref name='virConnectListSecrets'/> <ref name='virConnectListStoragePools'/> <ref name='virConnectNumOfDefinedDomains'/> <ref name='virConnectNumOfDefinedInterfaces'/> @@ -692,6 +715,7 @@ <ref name='virConnectNumOfDomains'/> <ref name='virConnectNumOfInterfaces'/> <ref name='virConnectNumOfNetworks'/> + <ref name='virConnectNumOfSecrets'/> <ref name='virConnectNumOfStoragePools'/> <ref name='virConnectOpen'/> <ref name='virConnectOpenAuth'/> @@ -851,6 +875,18 @@ <ref name='virSchedParameter'/> <ref name='virSchedParameterPtr'/> <ref name='virSchedParameterType'/> + <ref name='virSecret'/> + <ref name='virSecretDefineXML'/> + <ref name='virSecretFree'/> + <ref name='virSecretGetConnect'/> + <ref name='virSecretGetUUIDString'/> + <ref name='virSecretGetValue'/> + <ref name='virSecretGetXMLDesc'/> + <ref name='virSecretLookupByUUIDString'/> + <ref name='virSecretPtr'/> + <ref name='virSecretRef'/> + <ref name='virSecretSetValue'/> + <ref name='virSecretUndefine'/> <ref name='virSecurityLabel'/> <ref name='virSecurityLabelPtr'/> <ref name='virSecurityModel'/> @@ -913,6 +949,9 @@ </letter> </alpha> <constructors> + <type name='unsigned char *'> + <ref name='virSecretGetValue'/> + </type> <type name='unsigned int'> <ref name='virDomainGetID'/> </type> @@ -929,6 +968,7 @@ <ref name='virDomainGetConnect'/> <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </type> @@ -963,6 +1003,10 @@ <ref name='virNodeDeviceCreateXML'/> <ref name='virNodeDeviceLookupByName'/> </type> + <type name='virSecretPtr'> + <ref name='virSecretDefineXML'/> + <ref name='virSecretLookupByUUIDString'/> + </type> <type name='virStoragePoolPtr'> <ref name='virStoragePoolCreateXML'/> <ref name='virStoragePoolDefineXML'/> @@ -980,6 +1024,9 @@ </type> </constructors> <functions> + <type name='char **'> + <ref name='virConnectListSecrets'/> + </type> <type name='char ** const'> <ref name='virConnectListDefinedDomains'/> <ref name='virConnectListDefinedInterfaces'/> @@ -995,6 +1042,7 @@ <type name='const unsigned char *'> <ref name='virDomainLookupByUUID'/> <ref name='virNetworkLookupByUUID'/> + <ref name='virSecretSetValue'/> <ref name='virStoragePoolLookupByUUID'/> </type> <type name='int *'> @@ -1010,6 +1058,10 @@ <ref name='virDomainBlockStats'/> <ref name='virDomainInterfaceStats'/> <ref name='virDomainMemoryPeek'/> + <ref name='virSecretSetValue'/> + </type> + <type name='size_t *'> + <ref name='virSecretGetValue'/> </type> <type name='unsigned char *'> <ref name='virDomainGetUUID'/> @@ -1101,6 +1153,7 @@ <ref name='virConnectListDomains'/> <ref name='virConnectListInterfaces'/> <ref name='virConnectListNetworks'/> + <ref name='virConnectListSecrets'/> <ref name='virConnectListStoragePools'/> <ref name='virConnectNumOfDefinedDomains'/> <ref name='virConnectNumOfDefinedInterfaces'/> @@ -1109,6 +1162,7 @@ <ref name='virConnectNumOfDomains'/> <ref name='virConnectNumOfInterfaces'/> <ref name='virConnectNumOfNetworks'/> + <ref name='virConnectNumOfSecrets'/> <ref name='virConnectNumOfStoragePools'/> <ref name='virConnectRef'/> <ref name='virDomainCreateLinux'/> @@ -1136,6 +1190,8 @@ <ref name='virNodeGetSecurityModel'/> <ref name='virNodeListDevices'/> <ref name='virNodeNumOfDevices'/> + <ref name='virSecretDefineXML'/> + <ref name='virSecretLookupByUUIDString'/> <ref name='virStoragePoolCreateXML'/> <ref name='virStoragePoolDefineXML'/> <ref name='virStoragePoolLookupByName'/> @@ -1282,6 +1338,16 @@ <ref name='virDomainGetSchedulerParameters'/> <ref name='virDomainSetSchedulerParameters'/> </type> + <type name='virSecretPtr'> + <ref name='virSecretFree'/> + <ref name='virSecretGetConnect'/> + <ref name='virSecretGetUUIDString'/> + <ref name='virSecretGetValue'/> + <ref name='virSecretGetXMLDesc'/> + <ref name='virSecretRef'/> + <ref name='virSecretSetValue'/> + <ref name='virSecretUndefine'/> + </type> <type name='virSecurityLabelPtr'> <ref name='virDomainGetSecurityLabel'/> </type> @@ -1477,6 +1543,7 @@ <ref name='virConnectListDomains'/> <ref name='virConnectListInterfaces'/> <ref name='virConnectListNetworks'/> + <ref name='virConnectListSecrets'/> <ref name='virConnectListStoragePools'/> <ref name='virConnectNumOfDefinedDomains'/> <ref name='virConnectNumOfDefinedInterfaces'/> @@ -1485,6 +1552,7 @@ <ref name='virConnectNumOfDomains'/> <ref name='virConnectNumOfInterfaces'/> <ref name='virConnectNumOfNetworks'/> + <ref name='virConnectNumOfSecrets'/> <ref name='virConnectNumOfStoragePools'/> <ref name='virConnectOpen'/> <ref name='virConnectOpenAuth'/> @@ -1631,6 +1699,18 @@ <ref name='virSchedParameter'/> <ref name='virSchedParameterPtr'/> <ref name='virSchedParameterType'/> + <ref name='virSecret'/> + <ref name='virSecretDefineXML'/> + <ref name='virSecretFree'/> + <ref name='virSecretGetConnect'/> + <ref name='virSecretGetUUIDString'/> + <ref name='virSecretGetValue'/> + <ref name='virSecretGetXMLDesc'/> + <ref name='virSecretLookupByUUIDString'/> + <ref name='virSecretPtr'/> + <ref name='virSecretRef'/> + <ref name='virSecretSetValue'/> + <ref name='virSecretUndefine'/> <ref name='virSecurityLabel'/> <ref name='virSecurityLabelPtr'/> <ref name='virSecurityModel'/> @@ -1708,6 +1788,7 @@ <ref name='VIR_ERR_INVALID_MAC'/> <ref name='VIR_ERR_INVALID_NETWORK'/> <ref name='VIR_ERR_INVALID_NODE_DEVICE'/> + <ref name='VIR_ERR_INVALID_SECRET'/> <ref name='VIR_ERR_INVALID_STORAGE_POOL'/> <ref name='VIR_ERR_INVALID_STORAGE_VOL'/> <ref name='VIR_ERR_MULTIPLE_INTERFACES'/> @@ -1724,6 +1805,7 @@ <ref name='VIR_ERR_NO_NODE_DEVICE'/> <ref name='VIR_ERR_NO_OS'/> <ref name='VIR_ERR_NO_ROOT'/> + <ref name='VIR_ERR_NO_SECRET'/> <ref name='VIR_ERR_NO_SECURITY_MODEL'/> <ref name='VIR_ERR_NO_SOURCE'/> <ref name='VIR_ERR_NO_STORAGE_POOL'/> @@ -1767,6 +1849,7 @@ <ref name='VIR_FROM_QEMU'/> <ref name='VIR_FROM_REMOTE'/> <ref name='VIR_FROM_RPC'/> + <ref name='VIR_FROM_SECRET'/> <ref name='VIR_FROM_SECURITY'/> <ref name='VIR_FROM_SEXPR'/> <ref name='VIR_FROM_STATS_LINUX'/> @@ -1783,6 +1866,7 @@ <ref name='VIR_WAR_NO_INTERFACE'/> <ref name='VIR_WAR_NO_NETWORK'/> <ref name='VIR_WAR_NO_NODE'/> + <ref name='VIR_WAR_NO_SECRET'/> <ref name='VIR_WAR_NO_STORAGE'/> <ref name='_virError'/> <ref name='virConnCopyLastError'/> @@ -1966,6 +2050,9 @@ <ref name='virStoragePoolDelete'/> <ref name='virStorageVolDelete'/> </word> + <word name='Deletes'> + <ref name='virSecretUndefine'/> + </word> <word name='Depending'> <ref name='virNodeDeviceDettach'/> <ref name='virNodeDeviceReAttach'/> @@ -2042,6 +2129,7 @@ </letter> <letter name='F'> <word name='Fetch'> + <ref name='virConnectNumOfSecrets'/> <ref name='virNodeDeviceGetXMLDesc'/> <ref name='virStoragePoolGetName'/> <ref name='virStoragePoolGetUUID'/> @@ -2062,6 +2150,10 @@ <ref name='virStorageVolLookupByPath'/> </word> <word name='Fetches'> + <ref name='virSecretGetUUIDString'/> + <ref name='virSecretGetValue'/> + <ref name='virSecretGetXMLDesc'/> + <ref name='virSecretLookupByUUIDString'/> <ref name='virStoragePoolGetAutostart'/> <ref name='virStorageVolGetInfo'/> </word> @@ -2081,6 +2173,7 @@ <ref name='virNetworkGetUUIDString'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -2139,6 +2232,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -2156,6 +2250,7 @@ <ref name='virDomainGetConnect'/> <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -2199,6 +2294,7 @@ </word> <word name='List'> <ref name='_virConnectAuth'/> + <ref name='virConnectListSecrets'/> </word> <word name='Lists'> <ref name='virNodeDeviceListCaps'/> @@ -2297,6 +2393,9 @@ <word name='Optional'> <ref name='_virConnectCredential'/> </word> + <word name='Otherwise'> + <ref name='virSecretDefineXML'/> + </word> </letter> <letter name='P'> <word name='PCI'> @@ -2310,6 +2409,12 @@ <ref name='virEventUpdateHandleFunc'/> <ref name='virEventUpdateTimeoutFunc'/> </word> + <word name='Place'> + <ref name='virSecretGetValue'/> + </word> + <word name='Pointer'> + <ref name='virConnectListSecrets'/> + </word> <word name='Power'> <ref name='virNodeDeviceReset'/> </word> @@ -2345,6 +2450,7 @@ <ref name='virNetworkGetBridgeName'/> <ref name='virNetworkGetConnect'/> <ref name='virNodeNumOfDevices'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -2378,6 +2484,7 @@ <ref name='virConnectDomainEventRegister'/> </word> <word name='Release'> + <ref name='virSecretFree'/> <ref name='virStorageVolFree'/> </word> <word name='Remaining'> @@ -2431,6 +2538,7 @@ <ref name='virSetErrorFunc'/> </word> <word name='Sets'> + <ref name='virSecretSetValue'/> <ref name='virStoragePoolSetAutostart'/> </word> <word name='Shutdown'> @@ -2444,6 +2552,9 @@ <ref name='virConnGetLastError'/> <ref name='virDomainMigrate'/> </word> + <word name='Size'> + <ref name='virSecretSetValue'/> + </word> <word name='Some'> <ref name='virDomainMigrate'/> </word> @@ -2519,6 +2630,11 @@ <ref name='virNetworkGetUUIDString'/> <ref name='virNetworkLookupByUUID'/> <ref name='virNetworkLookupByUUIDString'/> + <ref name='virSecretDefineXML'/> + <ref name='virSecretGetUUIDString'/> + </word> + <word name='UUIDs'> + <ref name='virConnectListSecrets'/> </word> <word name='UUId'> <ref name='virDomainLookupByID'/> @@ -2578,6 +2694,9 @@ <ref name='virNetworkGetUUIDString'/> <ref name='virStoragePoolGetUUIDString'/> </word> + <word name='Value'> + <ref name='virSecretSetValue'/> + </word> </letter> </chunk> <chunk name='chunk2'> @@ -2586,6 +2705,7 @@ <ref name='virDomainGetConnect'/> <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -2596,6 +2716,7 @@ <ref name='virDomainGetConnect'/> <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -2690,6 +2811,7 @@ <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> <ref name='virNodeGetCellsFreeMemory'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -2739,6 +2861,8 @@ <ref name='virNetworkRef'/> <ref name='virNodeDeviceGetXMLDesc'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretDefineXML'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolFree'/> <ref name='virStoragePoolGetXMLDesc'/> <ref name='virStoragePoolRef'/> @@ -2806,6 +2930,7 @@ </word> <word name='any'> <ref name='virNodeDeviceDettach'/> + <ref name='virSecretDefineXML'/> <ref name='virStoragePoolDestroy'/> </word> <word name='anymore'> @@ -2827,6 +2952,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -2843,34 +2969,6 @@ <word name='archives'> <ref name='virConnectGetType'/> </word> - <word name='are'> - <ref name='virConnCopyLastError'/> - <ref name='virConnGetLastError'/> - <ref name='virConnectClose'/> - <ref name='virConnectGetHostname'/> - <ref name='virConnectListDefinedStoragePools'/> - <ref name='virConnectListStoragePools'/> - <ref name='virConnectOpen'/> - <ref name='virConnectOpenAuth'/> - <ref name='virConnectOpenReadOnly'/> - <ref name='virConnectRef'/> - <ref name='virDomainBlockPeek'/> - <ref name='virDomainDestroy'/> - <ref name='virDomainMemoryPeek'/> - <ref name='virDomainMigrate'/> - <ref name='virDomainPinVcpu'/> - <ref name='virDomainRef'/> - <ref name='virEventAddHandleFunc'/> - <ref name='virInterfaceRef'/> - <ref name='virNetworkDestroy'/> - <ref name='virNetworkRef'/> - <ref name='virNodeDeviceRef'/> - <ref name='virNodeDeviceReset'/> - <ref name='virSetErrorFunc'/> - <ref name='virStoragePoolRef'/> - <ref name='virStorageVolCreateXMLFrom'/> - <ref name='virStorageVolRef'/> - </word> <word name='area'> <ref name='virDomainBlockPeek'/> </word> @@ -2900,6 +2998,8 @@ <ref name='virInterfaceUndefine'/> <ref name='virNetworkDestroy'/> <ref name='virNetworkGetConnect'/> + <ref name='virSecretGetConnect'/> + <ref name='virSecretUndefine'/> <ref name='virStoragePoolDestroy'/> <ref name='virStoragePoolFree'/> <ref name='virStoragePoolGetConnect'/> @@ -2927,6 +3027,10 @@ <ref name='virConnectGetMaxVcpus'/> <ref name='virDomainBlockStats'/> </word> + <word name='attributes'> + <ref name='virSecretDefineXML'/> + <ref name='virSecretGetXMLDesc'/> + </word> <word name='authentication'> <ref name='virConnectOpenAuth'/> </word> @@ -2939,6 +3043,7 @@ <ref name='virDomainSetAutostart'/> <ref name='virNetworkGetAutostart'/> <ref name='virNetworkSetAutostart'/> + <ref name='virSecretDefineXML'/> <ref name='virStoragePoolGetAutostart'/> </word> <word name='autostart'> @@ -2995,6 +3100,7 @@ <ref name='virNetworkLookupByName'/> <ref name='virNetworkLookupByUUID'/> <ref name='virNetworkLookupByUUIDString'/> + <ref name='virSecretLookupByUUIDString'/> <ref name='virStoragePoolCreateXML'/> <ref name='virStoragePoolDefineXML'/> <ref name='virStoragePoolLookupByName'/> @@ -3045,6 +3151,7 @@ <ref name='virDomainGetConnect'/> <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -3156,6 +3263,10 @@ <ref name='virNodeDeviceRef'/> <ref name='virNodeGetCellsFreeMemory'/> <ref name='virSaveLastError'/> + <ref name='virSecretGetUUIDString'/> + <ref name='virSecretGetValue'/> + <ref name='virSecretGetXMLDesc'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -3264,6 +3375,9 @@ <word name='choose'> <ref name='virDomainMigrate'/> </word> + <word name='chosen'> + <ref name='virSecretDefineXML'/> + </word> <word name='clean'> <ref name='virResetError'/> </word> @@ -3385,6 +3499,7 @@ <ref name='virDomainSave'/> </word> <word name='continues'> + <ref name='virSecretFree'/> <ref name='virStorageVolFree'/> </word> <word name='control'> @@ -3414,6 +3529,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -3435,6 +3551,7 @@ <ref name='virNodeDeviceRef'/> <ref name='virNodeListDevices'/> <ref name='virNodeNumOfDevices'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -3442,6 +3559,7 @@ <ref name='virDomainGetConnect'/> <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -3474,6 +3592,9 @@ <word name='created'> <ref name='virNodeDeviceCreateXML'/> </word> + <word name='creates'> + <ref name='virSecretDefineXML'/> + </word> <word name='creation'> <ref name='virStoragePoolCreateXML'/> <ref name='virStoragePoolDefineXML'/> @@ -3491,6 +3612,7 @@ <word name='currently'> <ref name='virConnectDomainXMLFromNative'/> <ref name='virConnectDomainXMLToNative'/> + <ref name='virConnectNumOfSecrets'/> <ref name='virDomainCoreDump'/> <ref name='virNodeDeviceDettach'/> <ref name='virNodeDeviceReAttach'/> @@ -3554,8 +3676,10 @@ <word name='defined'> <ref name='virConnectListDefinedDomains'/> <ref name='virConnectListDefinedInterfaces'/> + <ref name='virConnectListSecrets'/> <ref name='virConnectNumOfDefinedDomains'/> <ref name='virConnectNumOfDefinedInterfaces'/> + <ref name='virConnectNumOfSecrets'/> <ref name='virDomainCreate'/> <ref name='virDomainUndefine'/> <ref name='virInterfaceCreate'/> @@ -3595,6 +3719,8 @@ <ref name='virConnectDomainXMLFromNative'/> <ref name='virConnectDomainXMLToNative'/> <ref name='virNodeDeviceGetXMLDesc'/> + <ref name='virSecretDefineXML'/> + <ref name='virSecretGetXMLDesc'/> <ref name='virStoragePoolGetXMLDesc'/> <ref name='virStorageVolGetXMLDesc'/> </word> @@ -3674,6 +3800,9 @@ <ref name='virDomainCreateXML'/> <ref name='virStoragePoolCreateXML'/> </word> + <word name='discarded'> + <ref name='virSecretDefineXML'/> + </word> <word name='discover'> <ref name='virConnectFindStoragePoolSources'/> </word> @@ -3701,6 +3830,7 @@ <ref name='virConnectDomainXMLToNative'/> <ref name='virConnectFindStoragePoolSources'/> <ref name='virNodeDeviceGetXMLDesc'/> + <ref name='virSecretGetXMLDesc'/> <ref name='virStoragePoolGetXMLDesc'/> <ref name='virStorageVolGetXMLDesc'/> </word> @@ -3725,6 +3855,7 @@ <ref name='virNetworkDefineXML'/> <ref name='virNetworkDestroy'/> <ref name='virNetworkUndefine'/> + <ref name='virSecretUndefine'/> <ref name='virStoragePoolDestroy'/> </word> <word name='doi'> @@ -3807,6 +3938,7 @@ <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> <ref name='virNodeGetCellsFreeMemory'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -3900,6 +4032,7 @@ <ref name='virConnectDomainEventRegister'/> </word> <word name='exist'> + <ref name='virSecretFree'/> <ref name='virStorageVolFree'/> </word> <word name='existing'> @@ -4031,6 +4164,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -4089,35 +4223,9 @@ <ref name='virGetVersion'/> <ref name='virInterfaceGetMACString'/> <ref name='virInterfaceLookupByMACString'/> + <ref name='virSecretGetUUIDString'/> <ref name='virStoragePoolGetXMLDesc'/> </word> - <word name='free'> - <ref name='_virStoragePoolInfo'/> - <ref name='virConnCopyLastError'/> - <ref name='virConnectDomainXMLFromNative'/> - <ref name='virConnectDomainXMLToNative'/> - <ref name='virConnectGetCapabilities'/> - <ref name='virCopyLastError'/> - <ref name='virDomainDestroy'/> - <ref name='virDomainGetSchedulerType'/> - <ref name='virDomainGetXMLDesc'/> - <ref name='virEventAddHandleFunc'/> - <ref name='virEventAddTimeoutFunc'/> - <ref name='virFreeError'/> - <ref name='virInterfaceDestroy'/> - <ref name='virInterfaceGetXMLDesc'/> - <ref name='virInterfaceUndefine'/> - <ref name='virNetworkDestroy'/> - <ref name='virNetworkGetBridgeName'/> - <ref name='virNetworkGetXMLDesc'/> - <ref name='virNodeGetCellsFreeMemory'/> - <ref name='virNodeGetFreeMemory'/> - <ref name='virSaveLastError'/> - <ref name='virStoragePoolDelete'/> - <ref name='virStoragePoolDestroy'/> - <ref name='virStoragePoolFree'/> - <ref name='virStoragePoolGetInfo'/> - </word> <word name='freeMems'> <ref name='virNodeGetCellsFreeMemory'/> </word> @@ -4158,6 +4266,7 @@ <ref name='virNodeDeviceDestroy'/> <ref name='virNodeDeviceDettach'/> <ref name='virNodeDeviceReAttach'/> + <ref name='virSecretDefineXML'/> <ref name='virStorageVolDelete'/> <ref name='virStorageVolGetKey'/> </word> @@ -4260,8 +4369,6 @@ <ref name='virNodeDeviceReset'/> </word> </letter> - </chunk> - <chunk name='chunk6'> <letter name='h'> <word name='handle'> <ref name='virConnectDomainEventRegister'/> @@ -4271,6 +4378,7 @@ <ref name='virEventRemoveHandleFunc'/> <ref name='virEventRemoveTimeoutFunc'/> <ref name='virEventTimeoutCallback'/> + <ref name='virSecretFree'/> <ref name='virStorageVolFree'/> </word> <word name='handler'> @@ -4316,6 +4424,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolGetKey'/> <ref name='virStorageVolRef'/> @@ -4329,6 +4438,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -4382,6 +4492,8 @@ <ref name='virDomainMigrate'/> </word> </letter> + </chunk> + <chunk name='chunk6'> <letter name='i'> <word name='iSCSI'> <ref name='virConnectFindStoragePoolSources'/> @@ -4442,6 +4554,7 @@ <ref name='virDomainGetConnect'/> <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -4451,6 +4564,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -4502,6 +4616,9 @@ <ref name='virDomainGetSecurityLabel'/> <ref name='virNodeGetSecurityModel'/> </word> + <word name='initializes'> + <ref name='virSecretDefineXML'/> + </word> <word name='initializing'> <ref name='virInitialize'/> <ref name='virStoragePoolRefresh'/> @@ -4593,6 +4710,7 @@ <ref name='virNetworkLookupByUUIDString'/> <ref name='virNodeDeviceLookupByName'/> <ref name='virNodeDeviceReAttach'/> + <ref name='virSecretDefineXML'/> <ref name='virStoragePoolCreateXML'/> <ref name='virStoragePoolDefineXML'/> <ref name='virStoragePoolLookupByName'/> @@ -4610,8 +4728,6 @@ <ref name='virStoragePoolDelete'/> </word> </letter> - </chunk> - <chunk name='chunk7'> <letter name='j'> <word name='join'> <ref name='virNetworkGetBridgeName'/> @@ -4664,6 +4780,7 @@ <ref name='virDomainGetConnect'/> <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -4754,6 +4871,7 @@ <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> <ref name='virNodeGetFreeMemory'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -4833,6 +4951,9 @@ <ref name='virStoragePoolGetName'/> <ref name='virStorageVolLookupByPath'/> </word> + <word name='locates'> + <ref name='virSecretDefineXML'/> + </word> <word name='location'> <ref name='virStoragePoolGetAutostart'/> </word> @@ -4847,6 +4968,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -4871,6 +4993,8 @@ <ref name='virDomainPinVcpu'/> </word> </letter> + </chunk> + <chunk name='chunk7'> <letter name='m'> <word name='machine'> <ref name='virDomainGetAutostart'/> @@ -4984,6 +5108,7 @@ <ref name='virNodeDeviceDettach'/> <ref name='virNodeDeviceReAttach'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolGetXMLDesc'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> @@ -5071,6 +5196,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -5095,13 +5221,14 @@ <ref name='virNetworkGetBridgeName'/> <ref name='virNetworkGetXMLDesc'/> <ref name='virNodeGetCellsFreeMemory'/> + <ref name='virSecretGetUUIDString'/> + <ref name='virSecretGetValue'/> + <ref name='virSecretGetXMLDesc'/> </word> <word name='mysterious'> <ref name='_virDomainBlockStats'/> </word> </letter> - </chunk> - <chunk name='chunk8'> <letter name='n'> <word name='names'> <ref name='virConnectListDefinedDomains'/> @@ -5110,6 +5237,7 @@ <ref name='virConnectListDefinedStoragePools'/> <ref name='virConnectListInterfaces'/> <ref name='virConnectListNetworks'/> + <ref name='virConnectListSecrets'/> <ref name='virConnectListStoragePools'/> <ref name='virNodeDeviceListCaps'/> <ref name='virNodeListDevices'/> @@ -5126,6 +5254,9 @@ <ref name='virConnectDomainXMLFromNative'/> <ref name='virConnectDomainXMLToNative'/> </word> + <word name='necessarily'> + <ref name='virSecretGetUUIDString'/> + </word> <word name='necessary'> <ref name='VIR_NODEINFO_MAXCPUS'/> <ref name='virConnectOpenAuth'/> @@ -5152,6 +5283,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -5224,6 +5356,8 @@ <ref name='virInterfaceLookupByMACString'/> </word> </letter> + </chunk> + <chunk name='chunk8'> <letter name='o'> <word name='objects'> <ref name='virDomainSetSchedulerParameters'/> @@ -5262,6 +5396,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -5304,6 +5439,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -5359,6 +5495,7 @@ <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> <ref name='virNodeDeviceReset'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -5515,6 +5652,7 @@ <word name='pointers'> <ref name='virConnectListDefinedDomains'/> <ref name='virConnectListDefinedNetworks'/> + <ref name='virConnectListSecrets'/> <ref name='virDomainMemoryPeek'/> </word> <word name='pools'> @@ -5604,6 +5742,7 @@ <ref name='virConnSetErrorFunc'/> <ref name='virConnectListDefinedDomains'/> <ref name='virConnectListDefinedNetworks'/> + <ref name='virConnectListSecrets'/> <ref name='virErrorFunc'/> <ref name='virEventAddHandleFunc'/> <ref name='virSetErrorFunc'/> @@ -5735,6 +5874,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -5754,6 +5894,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -5789,6 +5930,9 @@ <word name='renaming'> <ref name='virDomainMigrate'/> </word> + <word name='replaces'> + <ref name='virSecretDefineXML'/> + </word> <word name='reported'> <ref name='virConnCopyLastError'/> <ref name='virConnGetLastError'/> @@ -5828,6 +5972,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -6022,6 +6167,10 @@ <ref name='virDomainMigrate'/> <ref name='virStorageVolGetName'/> </word> + <word name='secrets'> + <ref name='virConnectListSecrets'/> + <ref name='virConnectNumOfSecrets'/> + </word> <word name='security'> <ref name='virDomainGetSecurityLabel'/> <ref name='virNodeGetSecurityModel'/> @@ -6080,6 +6229,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -6172,6 +6322,11 @@ <ref name='virDomainMigrate'/> <ref name='virNodeListDevices'/> <ref name='virNodeNumOfDevices'/> + <ref name='virSecretDefineXML'/> + <ref name='virSecretUndefine'/> + </word> + <word name='specifies'> + <ref name='virSecretDefineXML'/> </word> <word name='specify'> <ref name='virDomainMigrate'/> @@ -6256,12 +6411,14 @@ <ref name='virConnectListDomains'/> <ref name='virConnectListInterfaces'/> <ref name='virConnectListNetworks'/> + <ref name='virConnectListSecrets'/> <ref name='virConnectOpen'/> <ref name='virDomainGetConnect'/> <ref name='virDomainGetVcpus'/> <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> <ref name='virNodeListDevices'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetAutostart'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStoragePoolGetInfo'/> @@ -6275,6 +6432,9 @@ <ref name='virConnectListDefinedDomains'/> <ref name='virConnectListDefinedNetworks'/> </word> + <word name='storing'> + <ref name='virSecretGetValue'/> + </word> <word name='structure'> <ref name='virDomainBlockStats'/> <ref name='virDomainFree'/> @@ -6453,6 +6613,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virSetErrorFunc'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> @@ -6478,6 +6639,7 @@ <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> <ref name='virResetLastError'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -6494,6 +6656,7 @@ <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> <ref name='virResetLastError'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -6521,6 +6684,7 @@ <ref name='virDomainGetConnect'/> <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -6571,6 +6735,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -6595,6 +6760,7 @@ <ref name='virDomainMigrate'/> <ref name='virDomainPinVcpu'/> <ref name='virDomainSetVcpus'/> + <ref name='virSecretFree'/> <ref name='virStoragePoolBuild'/> <ref name='virStoragePoolDelete'/> <ref name='virStorageVolFree'/> @@ -6640,6 +6806,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolDefineXML'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> @@ -6701,6 +6868,7 @@ <ref name='virNodeDeviceDettach'/> <ref name='virNodeDeviceReAttach'/> <ref name='virNodeDeviceReset'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolBuild'/> <ref name='virStoragePoolCreate'/> <ref name='virStoragePoolCreateXML'/> @@ -6717,6 +6885,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -6756,6 +6925,7 @@ <ref name='virNodeDeviceCreateXML'/> <ref name='virNodeDeviceDettach'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolCreateXMLFrom'/> <ref name='virStorageVolRef'/> @@ -6763,6 +6933,12 @@ <word name='usual'> <ref name='virDomainMigrate'/> </word> + <word name='uuid'> + <ref name='virSecretLookupByUUIDString'/> + </word> + <word name='uuids'> + <ref name='virConnectListSecrets'/> + </word> </letter> </chunk> <chunk name='chunk12'> @@ -6770,29 +6946,6 @@ <word name='valid'> <ref name='virConnectDomainEventRegister'/> </word> - <word name='value'> - <ref name='VIR_CPU_USABLE'/> - <ref name='VIR_SECURITY_LABEL_BUFLEN'/> - <ref name='_virVcpuInfo'/> - <ref name='virConnectDomainXMLFromNative'/> - <ref name='virConnectDomainXMLToNative'/> - <ref name='virConnectGetMaxVcpus'/> - <ref name='virConnectGetVersion'/> - <ref name='virDomainGetAutostart'/> - <ref name='virDomainGetSchedulerParameters'/> - <ref name='virDomainGetSchedulerType'/> - <ref name='virDomainGetXMLDesc'/> - <ref name='virDomainSetSchedulerParameters'/> - <ref name='virEventAddTimeoutFunc'/> - <ref name='virEventUpdateTimeoutFunc'/> - <ref name='virGetVersion'/> - <ref name='virInterfaceGetXMLDesc'/> - <ref name='virNetworkGetAutostart'/> - <ref name='virNetworkGetBridgeName'/> - <ref name='virNetworkGetXMLDesc'/> - <ref name='virNodeGetFreeMemory'/> - <ref name='virStoragePoolGetAutostart'/> - </word> <word name='values'> <ref name='_virConnectAuth'/> <ref name='virDomainGetSchedulerParameters'/> @@ -6824,6 +6977,10 @@ </word> <word name='virConnect'> <ref name='virConnectDomainEventCallback'/> + <ref name='virConnectListSecrets'/> + <ref name='virConnectNumOfSecrets'/> + <ref name='virSecretDefineXML'/> + <ref name='virSecretLookupByUUIDString'/> </word> <word name='virConnectClose'> <ref name='virConnectRef'/> @@ -6850,6 +7007,7 @@ <ref name='virDomainGetConnect'/> <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -6988,6 +7146,20 @@ <word name='virSchedParameter'> <ref name='VIR_DOMAIN_SCHED_FIELD_LENGTH'/> </word> + <word name='virSecret'> + <ref name='virSecretGetConnect'/> + <ref name='virSecretGetUUIDString'/> + <ref name='virSecretGetValue'/> + <ref name='virSecretGetXMLDesc'/> + <ref name='virSecretSetValue'/> + <ref name='virSecretUndefine'/> + </word> + <word name='virSecretFree'> + <ref name='virSecretRef'/> + </word> + <word name='virSecretPtr'> + <ref name='virSecretUndefine'/> + </word> <word name='virSecurityLabel'> <ref name='VIR_SECURITY_LABEL_BUFLEN'/> <ref name='virDomainGetSecurityLabel'/> @@ -7129,6 +7301,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -7184,6 +7357,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -7194,6 +7368,7 @@ <ref name='virDomainGetConnect'/> <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -7213,6 +7388,7 @@ </word> <word name='xml'> <ref name='virConnectFindStoragePoolSources'/> + <ref name='virSecretDefineXML'/> </word> <word name='xvda'> <ref name='virDomainBlockStats'/> @@ -7253,10 +7429,10 @@ <chunk name='chunk2' start='W' end='a'/> <chunk name='chunk3' start='b' end='c'/> <chunk name='chunk4' start='d' end='e'/> - <chunk name='chunk5' start='f' end='g'/> - <chunk name='chunk6' start='h' end='i'/> - <chunk name='chunk7' start='j' end='m'/> - <chunk name='chunk8' start='n' end='p'/> + <chunk name='chunk5' start='f' end='h'/> + <chunk name='chunk6' start='i' end='l'/> + <chunk name='chunk7' start='m' end='n'/> + <chunk name='chunk8' start='o' end='p'/> <chunk name='chunk9' start='q' end='r'/> <chunk name='chunk10' start='s' end='s'/> <chunk name='chunk11' start='t' end='u'/> -- 1.6.2.5

On Sun, Aug 16, 2009 at 10:48:02PM +0200, Miloslav Trmač wrote:
This commit represents results of (make -C docs api) - if this patch does not apply, just re-run the command.
The API data gathered by this commit is necessary to make step 10 (Python bindings) usable.
Okay, I usually don't make apply such patch but rather regenerate, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Sample session:
import libvirt c = libvirt.open('qemu:///session')
c.listSecrets() ['12247729-47d2-a783-88ce-b329d4781cd3', 'reee', 'abc']
s = c.secretDefineXML("<secret ephemeral='no' private='no'>\n<description>Something for use</description>\n<volume>/foo/bar</volume>\n</secret>\n")
s.getUUIDString() '340c2dfb-811b-eda8-da9e-25ccd7bfd650'
s.getXMLDesc() "<secret ephemeral='no' private='no'>\n <uuid>340c2dfb-811b-eda8-da9e-25ccd7bfd650</uuid>\n <description>Something for use</description>\n <volume>/foo/bar</volume>\n</secret>\n"
s.setValue('abc\0xx\xffx') 0
s.getValue() 'abc\x00xx\xffx'
s.undefine() 0
Changes since the second submission: - Update for new public API - s/secret_id/uuid/g - Use "unsigned char *" for secret value --- python/generator.py | 28 ++++++++++-- python/libvir.c | 96 +++++++++++++++++++++++++++++++++++++++++ python/libvirt-python-api.xml | 16 +++++++ python/libvirt_wrap.h | 9 ++++ python/types.c | 13 ++++++ 5 files changed, 158 insertions(+), 4 deletions(-) diff --git a/python/generator.py b/python/generator.py index feff7a3..b9b0ecb 100755 --- a/python/generator.py +++ b/python/generator.py @@ -270,6 +270,11 @@ py_types = { 'const virNodeDevicePtr': ('O', "virNodeDevice", "virNodeDevicePtr", "virNodeDevicePtr"), 'virNodeDevice *': ('O', "virNodeDevice", "virNodeDevicePtr", "virNodeDevicePtr"), 'const virNodeDevice *': ('O', "virNodeDevice", "virNodeDevicePtr", "virNodeDevicePtr"), + + 'virSecretPtr': ('O', "virSecret", "virSecretPtr", "virSecretPtr"), + 'const virSecretPtr': ('O', "virSecret", "virSecretPtr", "virSecretPtr"), + 'virSecret *': ('O', "virSecret", "virSecretPtr", "virSecretPtr"), + 'const virSecret *': ('O', "virSecret", "virSecretPtr", "virSecretPtr"), } py_return_types = { @@ -296,6 +301,7 @@ skip_impl = ( 'virConnectListDefinedNetworks', 'virConnectListInterfaces', 'virConnectListDefinedInterfaces', + 'virConnectListSecrets', 'virConnectListStoragePools', 'virConnectListDefinedStoragePools', 'virConnectListStorageVols', @@ -320,6 +326,8 @@ skip_impl = ( 'virDomainSetSchedulerParameters', 'virDomainGetVcpus', 'virDomainPinVcpu', + 'virSecretGetValue', + 'virSecretSetValue', 'virStoragePoolGetUUID', 'virStoragePoolGetUUIDString', 'virStoragePoolLookupByUUID', @@ -623,6 +631,8 @@ classes_type = { "virStorageVol *": ("._o", "virStorageVol(self, _obj=%s)", "virStorageVol"), "virNodeDevicePtr": ("._o", "virNodeDevice(self, _obj=%s)", "virNodeDevice"), "virNodeDevice *": ("._o", "virNodeDevice(self, _obj=%s)", "virNodeDevice"), + "virSecretPtr": ("._o", "virSecret(self, _obj=%s)", "virSecret"), + "virSecret *": ("._o", "virSecret(self, _obj=%s)", "virSecret"), "virConnectPtr": ("._o", "virConnect(_obj=%s)", "virConnect"), "virConnect *": ("._o", "virConnect(_obj=%s)", "virConnect"), } @@ -632,7 +642,7 @@ converter_type = { primary_classes = ["virDomain", "virNetwork", "virInterface", "virStoragePool", "virStorageVol", - "virConnect", "virNodeDevice" ] + "virConnect", "virNodeDevice", "virSecret" ] classes_ancestor = { } @@ -642,7 +652,8 @@ classes_destructors = { "virInterface": "virInterfaceFree", "virStoragePool": "virStoragePoolFree", "virStorageVol": "virStorageVolFree", - "virNodeDevice" : "virNodeDeviceFree" + "virNodeDevice" : "virNodeDeviceFree", + "virSecret": "virSecretFree" } functions_noexcept = { @@ -714,6 +725,12 @@ def nameFixup(name, classe, type, file): elif name[0:18] == "virInterfaceLookup": func = name[3:] func = string.lower(func[0:1]) + func[1:] + elif name[0:15] == "virSecretDefine": + func = name[3:] + func = string.lower(func[0:1]) + func[1:] + elif name[0:15] == "virSecretLookup": + func = name[3:] + func = string.lower(func[0:1]) + func[1:] elif name[0:20] == "virStoragePoolDefine": func = name[3:] func = string.lower(func[0:1]) + func[1:] @@ -747,6 +764,9 @@ def nameFixup(name, classe, type, file): elif name[0:12] == "virInterface": func = name[10:] func = string.lower(func[0:1]) + func[1:] + elif name[0:9] == 'virSecret': + func = name[9:] + func = string.lower(func[0:1]) + func[1:] elif name[0:17] == "virStoragePoolGet": func = name[17:] func = string.lower(func[0:1]) + func[1:] @@ -1018,7 +1038,7 @@ def buildWrappers(): else: txt.write("Class %s()\n" % (classname)) classes.write("class %s:\n" % (classname)) - if classname in [ "virDomain", "virNetwork", "virInterface", "virStoragePool", "virStorageVol", "virNodeDevice" ]: + if classname in [ "virDomain", "virNetwork", "virInterface", "virStoragePool", "virStorageVol", "virNodeDevice", "virSecret" ]: classes.write(" def __init__(self, conn, _obj=None):\n") else: classes.write(" def __init__(self, _obj=None):\n") @@ -1026,7 +1046,7 @@ def buildWrappers(): list = reference_keepers[classname] for ref in list: classes.write(" self.%s = None\n" % ref[1]) - if classname in [ "virDomain", "virNetwork", "virInterface", "virNodeDevice" ]: + if classname in [ "virDomain", "virNetwork", "virInterface", "virNodeDevice", "virSecret" ]: classes.write(" self._conn = conn\n") elif classname in [ "virStorageVol", "virStoragePool" ]: classes.write(" self._conn = conn\n" + \ diff --git a/python/libvir.c b/python/libvir.c index e210597..ca9ec26 100644 --- a/python/libvir.c +++ b/python/libvir.c @@ -1562,6 +1562,99 @@ libvirt_virNodeDeviceListCaps(PyObject *self ATTRIBUTE_UNUSED, return(py_retval); } +static PyObject * +libvirt_virConnectListSecrets(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) { + PyObject *py_retval; + char **uuids = NULL; + virConnectPtr conn; + int c_retval, i; + PyObject *pyobj_conn; + + if (!PyArg_ParseTuple(args, (char *)"O:virConnectListSecrets", &pyobj_conn)) + return NULL; + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virConnectNumOfSecrets(conn); + LIBVIRT_END_ALLOW_THREADS; + if (c_retval < 0) + return VIR_PY_NONE; + + if (c_retval) { + uuids = malloc(sizeof(*uuids) * c_retval); + if (!uuids) + return VIR_PY_NONE; + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virConnectListSecrets(conn, uuids, c_retval); + LIBVIRT_END_ALLOW_THREADS; + if (c_retval < 0) { + free(uuids); + return VIR_PY_NONE; + } + } + py_retval = PyList_New(c_retval); + + if (uuids) { + for (i = 0;i < c_retval;i++) { + PyList_SetItem(py_retval, i, libvirt_constcharPtrWrap(uuids[i])); + free(uuids[i]); + } + free(uuids); + } + + return py_retval; +} + +static PyObject * +libvirt_virSecretGetValue(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) { + PyObject *py_retval; + unsigned char *c_retval; + size_t size; + virSecretPtr secret; + PyObject *pyobj_secret; + + if (!PyArg_ParseTuple(args, (char *)"O:virSecretGetValue", &pyobj_secret)) + return NULL; + secret = (virSecretPtr) PyvirSecret_Get(pyobj_secret); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virSecretGetValue(secret, &size); + LIBVIRT_END_ALLOW_THREADS; + + if (c_retval == NULL) + return VIR_PY_NONE; + + py_retval = PyString_FromStringAndSize((const char *)c_retval, size); + memset(c_retval, 0, size); + free(c_retval); + + return py_retval; +} + +static PyObject * +libvirt_virSecretSetValue(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) { + PyObject *py_retval; + int c_retval; + virSecretPtr secret; + PyObject *pyobj_secret; + const char *value; + int size; + + if (!PyArg_ParseTuple(args, (char *)"Oz#:virSecretSetValue", &pyobj_secret, + &value, &size)) + return NULL; + secret = (virSecretPtr) PyvirSecret_Get(pyobj_secret); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virSecretSetValue(secret, (const unsigned char *)value, size); + LIBVIRT_END_ALLOW_THREADS; + + py_retval = libvirt_intWrap(c_retval); + return py_retval; +} /******************************************* * Helper functions to avoid importing modules @@ -2261,6 +2354,9 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virEventInvokeTimeoutCallback", libvirt_virEventInvokeTimeoutCallback, METH_VARARGS, NULL}, {(char *) "virNodeListDevices", libvirt_virNodeListDevices, METH_VARARGS, NULL}, {(char *) "virNodeDeviceListCaps", libvirt_virNodeDeviceListCaps, METH_VARARGS, NULL}, + {(char *) "virConnectListSecrets", libvirt_virConnectListSecrets, METH_VARARGS, NULL}, + {(char *) "virSecretGetValue", libvirt_virSecretGetValue, METH_VARARGS, NULL}, + {(char *) "virSecretSetValue", libvirt_virSecretSetValue, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL} }; diff --git a/python/libvirt-python-api.xml b/python/libvirt-python-api.xml index 43a5b4e..97193d8 100644 --- a/python/libvirt-python-api.xml +++ b/python/libvirt-python-api.xml @@ -172,5 +172,21 @@ <arg name='dev' type='virNodeDevicePtr' info='pointer to the node device'/> <return type='str *' info='the list of Names or None in case of error'/> </function> + <function name='virSecretGetValue' file='libvirt' module='libvirt'> + <info>Fetches the value associated with a secret.</info> + <return type='char *' info='the secret value or None in case of error'/> + <arg name='secret' type='virSecretPtr' info='virSecret secret'/> + </function> + <function name='virConnectListSecrets' file='libvirt' module='libvirt'> + <info>List the defined secret IDs</info> + <arg name='conn' type='virConnectPtr' info='virConnect connection'/> + <return type='str *' info='the list of secret IDs or None in case of error'/> + </function> + <function name='virSecretSetValue' file='libvirt' module='libvirt'> + <info>Associates a value with a secret.</info> + <return type='int' info='0 on success, -1 on failure.'/> + <arg name='secret' type='virSecretPtr' info='virSecret secret'/> + <arg name='value' type='const char *' info='The secret value'/> + </function> </symbols> </api> diff --git a/python/libvirt_wrap.h b/python/libvirt_wrap.h index 4a32edd..99d5805 100644 --- a/python/libvirt_wrap.h +++ b/python/libvirt_wrap.h @@ -83,6 +83,14 @@ typedef struct { virNodeDevicePtr obj; } PyvirNodeDevice_Object; +#define PyvirSecret_Get(v) (((v) == Py_None) ? NULL : \ + (((PyvirSecret_Object *)(v))->obj)) + +typedef struct { + PyObject_HEAD + virSecretPtr obj; +} PyvirSecret_Object; + #define PyvirEventHandleCallback_Get(v) (((v) == Py_None) ? NULL : \ (((PyvirEventHandleCallback_Object *)(v))->obj)) @@ -135,6 +143,7 @@ PyObject * libvirt_virEventTimeoutCallbackWrap(virEventTimeoutCallback node); PyObject * libvirt_virFreeCallbackWrap(virFreeCallback node); PyObject * libvirt_virVoidPtrWrap(void* node); PyObject * libvirt_virNodeDevicePtrWrap(virNodeDevicePtr node); +PyObject * libvirt_virSecretPtrWrap(virSecretPtr node); /* Provide simple macro statement wrappers (adapted from GLib, in turn from Perl): diff --git a/python/types.c b/python/types.c index de75471..c445f5f 100644 --- a/python/types.c +++ b/python/types.c @@ -194,6 +194,19 @@ libvirt_virNodeDevicePtrWrap(virNodeDevicePtr node) } PyObject * +libvirt_virSecretPtrWrap(virSecretPtr node) +{ + PyObject *ret; + + if (node == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + ret = PyCObject_FromVoidPtrAndDesc(node, (char *) "virSecretPtr", NULL); + return (ret); +} + +PyObject * libvirt_virEventHandleCallbackWrap(virEventHandleCallback node) { PyObject *ret; -- 1.6.2.5

On Sun, Aug 16, 2009 at 10:48:03PM +0200, Miloslav Trmač wrote: okay,
@@ -714,6 +725,12 @@ def nameFixup(name, classe, type, file): elif name[0:18] == "virInterfaceLookup": func = name[3:] func = string.lower(func[0:1]) + func[1:] + elif name[0:15] == "virSecretDefine": + func = name[3:] + func = string.lower(func[0:1]) + func[1:] + elif name[0:15] == "virSecretLookup": + func = name[3:] + func = string.lower(func[0:1]) + func[1:] elif name[0:20] == "virStoragePoolDefine": func = name[3:] func = string.lower(func[0:1]) + func[1:] @@ -747,6 +764,9 @@ def nameFixup(name, classe, type, file): elif name[0:12] == "virInterface": func = name[10:] func = string.lower(func[0:1]) + func[1:] + elif name[0:9] == 'virSecret': + func = name[9:] + func = string.lower(func[0:1]) + func[1:] elif name[0:17] == "virStoragePoolGet": func = name[17:] func = string.lower(func[0:1]) + func[1:]
That part of the patch is likely to clash with my current attempt at cleaning this up but that should be easy to apply manually. ACK looks fine :-) Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Define an <encryption> tag specifying volume encryption format and format-depenedent parameters (e.g. passphrase, cipher name, key length, key). Currently the only defined parameter is a reference to a "secret" (passphrase/key) managed using the virSecret* API. Only the qcow/qcow2 encryption format, and a "default" format used to let libvirt choose the format during volume creation, is currently supported. This patch does not add any users; the <encryption> tag is added in the following patches to both volumes (to support encrypted volume creation) and domains. Changes since the second submission; - Remove <optional> from the <encryption> schema - Drop <encryption format='unencrypted'/> - s/secret_id/uuid/g - Fix indentation --- bootstrap | 1 + docs/format.html | 4 + docs/formatcaps.html | 4 + docs/formatdomain.html | 4 + docs/formatnetwork.html | 4 + docs/formatnode.html | 4 + docs/formatsecret.html | 4 + docs/formatstorage.html | 4 + docs/formatstorageencryption.html | 209 +++++++++++++++++++++++++++++ docs/formatstorageencryption.html.in | 65 +++++++++ docs/schemas/Makefile.am | 1 + docs/schemas/storageencryption.rng | 34 +++++ docs/sitemap.html | 3 + docs/sitemap.html.in | 4 + po/POTFILES.in | 1 + src/Makefile.am | 1 + src/libvirt_private.syms | 5 + src/storage_encryption.c | 241 ++++++++++++++++++++++++++++++++++ src/storage_encryption.h | 72 ++++++++++ 19 files changed, 665 insertions(+), 0 deletions(-) create mode 100644 docs/formatstorageencryption.html create mode 100644 docs/formatstorageencryption.html.in create mode 100644 docs/schemas/storageencryption.rng create mode 100644 src/storage_encryption.c create mode 100644 src/storage_encryption.h diff --git a/bootstrap b/bootstrap index 8b81e0e..885b299 100755 --- a/bootstrap +++ b/bootstrap @@ -65,6 +65,7 @@ gnulib_tool=$GNULIB_SRCDIR/gnulib-tool <$gnulib_tool || exit modules=' +base64 c-ctype close connect diff --git a/docs/format.html b/docs/format.html index 3c20b5f..e8b1498 100644 --- a/docs/format.html +++ b/docs/format.html @@ -64,6 +64,10 @@ </div> </li><li> <div> + <a title="Storage volume encryption XML format" class="inactive" href="formatstorageencryption.html">Storage Encryption</a> + </div> + </li><li> + <div> <a title="The driver capabilities XML format" class="inactive" href="formatcaps.html">Capabilities</a> </div> </li><li> diff --git a/docs/formatcaps.html b/docs/formatcaps.html index 5f2bc72..3240101 100644 --- a/docs/formatcaps.html +++ b/docs/formatcaps.html @@ -64,6 +64,10 @@ </div> </li><li> <div> + <a title="Storage volume encryption XML format" class="inactive" href="formatstorageencryption.html">Storage Encryption</a> + </div> + </li><li> + <div> <span class="active">Capabilities</span> </div> </li><li> diff --git a/docs/formatdomain.html b/docs/formatdomain.html index 6b655ad..efba65a 100644 --- a/docs/formatdomain.html +++ b/docs/formatdomain.html @@ -64,6 +64,10 @@ </div> </li><li> <div> + <a title="Storage volume encryption XML format" class="inactive" href="formatstorageencryption.html">Storage Encryption</a> + </div> + </li><li> + <div> <a title="The driver capabilities XML format" class="inactive" href="formatcaps.html">Capabilities</a> </div> </li><li> diff --git a/docs/formatnetwork.html b/docs/formatnetwork.html index 72a3cda..845e558 100644 --- a/docs/formatnetwork.html +++ b/docs/formatnetwork.html @@ -64,6 +64,10 @@ </div> </li><li> <div> + <a title="Storage volume encryption XML format" class="inactive" href="formatstorageencryption.html">Storage Encryption</a> + </div> + </li><li> + <div> <a title="The driver capabilities XML format" class="inactive" href="formatcaps.html">Capabilities</a> </div> </li><li> diff --git a/docs/formatnode.html b/docs/formatnode.html index 516c27b..b269baa 100644 --- a/docs/formatnode.html +++ b/docs/formatnode.html @@ -64,6 +64,10 @@ </div> </li><li> <div> + <a title="Storage volume encryption XML format" class="inactive" href="formatstorageencryption.html">Storage Encryption</a> + </div> + </li><li> + <div> <a title="The driver capabilities XML format" class="inactive" href="formatcaps.html">Capabilities</a> </div> </li><li> diff --git a/docs/formatsecret.html b/docs/formatsecret.html index 998e874..929eb86 100644 --- a/docs/formatsecret.html +++ b/docs/formatsecret.html @@ -64,6 +64,10 @@ </div> </li><li> <div> + <a title="Storage volume encryption XML format" class="inactive" href="formatstorageencryption.html">Storage Encryption</a> + </div> + </li><li> + <div> <a title="The driver capabilities XML format" class="inactive" href="formatcaps.html">Capabilities</a> </div> </li><li> diff --git a/docs/formatstorage.html b/docs/formatstorage.html index 02cbcac..8c16a0f 100644 --- a/docs/formatstorage.html +++ b/docs/formatstorage.html @@ -64,6 +64,10 @@ </div> </li><li> <div> + <a title="Storage volume encryption XML format" class="inactive" href="formatstorageencryption.html">Storage Encryption</a> + </div> + </li><li> + <div> <a title="The driver capabilities XML format" class="inactive" href="formatcaps.html">Capabilities</a> </div> </li><li> diff --git a/docs/formatstorageencryption.html b/docs/formatstorageencryption.html new file mode 100644 index 0000000..15175fe --- /dev/null +++ b/docs/formatstorageencryption.html @@ -0,0 +1,209 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<!-- + This file is autogenerated from formatstorageencryption.html.in + Do not edit this file. Changes will be lost. + --> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /> + <link rel="stylesheet" type="text/css" href="main.css" /> + <link rel="SHORTCUT ICON" href="32favicon.png" /> + <title>libvirt: Storage volume encryption XML format</title> + <meta name="description" content="libvirt, virtualization, virtualization API" /> + </head> + <body> + <div id="header"> + <div id="headerLogo"></div> + <div id="headerSearch"> + <form action="search.php" enctype="application/x-www-form-urlencoded" method="get"><div> + <input id="query" name="query" type="text" size="12" value="" /> + <input id="submit" name="submit" type="submit" value="Search" /> + </div></form> + </div> + </div> + <div id="body"> + <div id="menu"> + <ul class="l0"><li> + <div> + <a title="Front page of the libvirt website" class="inactive" href="index.html">Home</a> + </div> + </li><li> + <div> + <a title="Details of new features and bugs fixed in each release" class="inactive" href="news.html">News</a> + </div> + </li><li> + <div> + <a title="Get the latest source releases, binary builds and get access to the source repository" class="inactive" href="downloads.html">Downloads</a> + </div> + </li><li> + <div> + <a title="Information for users, administrators and developers" class="active" href="docs.html">Documentation</a> + <ul class="l1"><li> + <div> + <a title="Information about deploying and using libvirt" class="inactive" href="deployment.html">Deployment</a> + </div> + </li><li> + <div> + <a title="Overview of the logical subsystems in the libvirt API" class="inactive" href="intro.html">Architecture</a> + </div> + </li><li> + <div> + <a title="Description of the XML formats used in libvirt" class="active" href="format.html">XML format</a> + <ul class="l2"><li> + <div> + <a title="The domain XML format" class="inactive" href="formatdomain.html">Domains</a> + </div> + </li><li> + <div> + <a title="The virtual network XML format" class="inactive" href="formatnetwork.html">Networks</a> + </div> + </li><li> + <div> + <a title="The storage pool and volume XML format" class="inactive" href="formatstorage.html">Storage</a> + </div> + </li><li> + <div> + <span class="active">Storage Encryption</span> + </div> + </li><li> + <div> + <a title="The driver capabilities XML format" class="inactive" href="formatcaps.html">Capabilities</a> + </div> + </li><li> + <div> + <a title="The host device XML format" class="inactive" href="formatnode.html">Node Devices</a> + </div> + </li><li> + <div> + <a title="The secret XML format" class="inactive" href="formatsecret.html">Secrets</a> + </div> + </li></ul> + </div> + </li><li> + <div> + <a title="Hypervisor specific driver information" class="inactive" href="drivers.html">Drivers</a> + </div> + </li><li> + <div> + <a title="Reference manual for the C public API" class="inactive" href="html/index.html">API reference</a> + </div> + </li><li> + <div> + <a title="Bindings of the libvirt API for other languages" class="inactive" href="bindings.html">Language bindings</a> + </div> + </li><li> + <div> + <a title="Working on the internals of libvirt API, driver and daemon code" class="inactive" href="internals.html">Internals</a> + </div> + </li></ul> + </div> + </li><li> + <div> + <a title="User contributed content" class="inactive" href="http://wiki.libvirt.org">Wiki</a> + </div> + </li><li> + <div> + <a title="Frequently asked questions" class="inactive" href="FAQ.html">FAQ</a> + </div> + </li><li> + <div> + <a title="How and where to report bugs and request features" class="inactive" href="bugs.html">Bug reports</a> + </div> + </li><li> + <div> + <a title="How to contact the developers via email and IRC" class="inactive" href="contact.html">Contact</a> + </div> + </li><li> + <div> + <a title="Miscellaneous links of interest related to libvirt" class="inactive" href="relatedlinks.html">Related Links</a> + </div> + </li><li> + <div> + <a title="Overview of all content on the website" class="inactive" href="sitemap.html">Sitemap</a> + </div> + </li></ul> + </div> + <div id="content"> + <h1>Storage volume encryption XML format</h1> + <ul><li> + <a href="#StorageEncryption">Storage volume encryption XML</a> + <ul><li> + <a href="#StorageEncryptionDefault">"default" format</a> + </li><li> + <a href="#StorageEncryptionQcow">"qcow" format</a> + </li></ul> + </li><li> + <a href="#example">Example</a> + </li></ul> + <h2> + <a name="StorageEncryption" id="StorageEncryption">Storage volume encryption XML</a> + </h2> + <p> + Storage volumes may be encrypted, the XML snippet described below is used + to represent the details of the encryption. It can be used as a part + of a domain or storage configuration. + </p> + <p> + The top-level tag of volume encryption specification + is <code>encryption</code>, with a mandatory + attribute <code>format</code>. Currently defined values + of <code>format</code> are <code>default</code> and <code>qcow</code>. + Each value of <code>format</code> implies some expectations about the + content of the <code>encryption</code> tag. Other format values may be + defined in the future. + </p> + <p> + The <code>encryption</code> tag can currently contain a sequence of + <code>secret</code> tags, each with mandatory attributes <code>type</code> + and <code>uuid</code>. The only currently defined value of + <code>type</code> is <code>passphrase</code>. <code>uuid</code> + refers to a secret known to libvirt. libvirt can use a secret value + previously set using <code>virSecretSetValue()</code>, or, if supported + by the particular volume format and driver, automatically generate a + secret value at the time of volume creation, and store it using the + specified <code>uuid</code>. + </p> + <p> + </p> + <h3> + <a name="StorageEncryptionDefault" id="StorageEncryptionDefault">"default" format</a> + </h3> + <p> + <code><encryption type="default"/></code> can be specified only + when creating a volume. If the volume is successfully created, the + encryption formats, parameters and secrets will be auto-generated by + libvirt and the attached <code>encryption</code> tag will be updated. + The unmodified contents of the <code>encryption</code> tag can be used + in later operations with the volume, or when setting up a domain that + uses the volume. + </p> + <h3> + <a name="StorageEncryptionQcow" id="StorageEncryptionQcow">"qcow" format</a> + </h3> + <p> + The <code>qcow</code> format specifies that the built-in encryption + support in <code>qcow</code>- or <code>qcow2</code>-formatted volume + images should be used. A single + <code><secret type='passphrase'></code> element is expected. If + the <code>secret</code> element is not present during volume creation, + a secret is automatically generated and attached to the volume. + </p> + <h2> + <a name="example" id="example">Example</a> + </h2> + <p> + Here is a simple example, specifying use of the <code>qcow</code> format: + </p> + <pre> + <encryption format='qcow'> + <secret type='passphrase' uuid='c1f11a6d-8c5d-4a3e-ac7a-4e171c5e0d4a' /> + </encryption></pre> + </div> + </div> + <div id="footer"> + <p id="sponsor"> + Sponsored by:<br /><a href="http://et.redhat.com/"><img src="et.png" alt="Project sponsored by Red Hat Emerging Technology" /></a></p> + </div> + </body> +</html> diff --git a/docs/formatstorageencryption.html.in b/docs/formatstorageencryption.html.in new file mode 100644 index 0000000..0e5dcee --- /dev/null +++ b/docs/formatstorageencryption.html.in @@ -0,0 +1,65 @@ +<html> + <body> + <h1>Storage volume encryption XML format</h1> + + <ul id="toc"></ul> + + <h2><a name="StorageEncryption">Storage volume encryption XML</a></h2> + + <p> + Storage volumes may be encrypted, the XML snippet described below is used + to represent the details of the encryption. It can be used as a part + of a domain or storage configuration. + </p> + <p> + The top-level tag of volume encryption specification + is <code>encryption</code>, with a mandatory + attribute <code>format</code>. Currently defined values + of <code>format</code> are <code>default</code> and <code>qcow</code>. + Each value of <code>format</code> implies some expectations about the + content of the <code>encryption</code> tag. Other format values may be + defined in the future. + </p> + <p> + The <code>encryption</code> tag can currently contain a sequence of + <code>secret</code> tags, each with mandatory attributes <code>type</code> + and <code>uuid</code>. The only currently defined value of + <code>type</code> is <code>passphrase</code>. <code>uuid</code> + refers to a secret known to libvirt. libvirt can use a secret value + previously set using <code>virSecretSetValue()</code>, or, if supported + by the particular volume format and driver, automatically generate a + secret value at the time of volume creation, and store it using the + specified <code>uuid</code>. + <p> + <h3><a name="StorageEncryptionDefault">"default" format</a></h3> + <p> + <code><encryption type="default"/></code> can be specified only + when creating a volume. If the volume is successfully created, the + encryption formats, parameters and secrets will be auto-generated by + libvirt and the attached <code>encryption</code> tag will be updated. + The unmodified contents of the <code>encryption</code> tag can be used + in later operations with the volume, or when setting up a domain that + uses the volume. + </p> + <h3><a name="StorageEncryptionQcow">"qcow" format</a></h3> + <p> + The <code>qcow</code> format specifies that the built-in encryption + support in <code>qcow</code>- or <code>qcow2</code>-formatted volume + images should be used. A single + <code><secret type='passphrase'></code> element is expected. If + the <code>secret</code> element is not present during volume creation, + a secret is automatically generated and attached to the volume. + </p> + + <h2><a name="example">Example</a></h2> + + <p> + Here is a simple example, specifying use of the <code>qcow</code> format: + </p> + + <pre> + <encryption format='qcow'> + <secret type='passphrase' uuid='c1f11a6d-8c5d-4a3e-ac7a-4e171c5e0d4a' /> + </encryption></pre> + </body> +</html> diff --git a/docs/schemas/Makefile.am b/docs/schemas/Makefile.am index a064518..c217d69 100644 --- a/docs/schemas/Makefile.am +++ b/docs/schemas/Makefile.am @@ -6,6 +6,7 @@ schema_DATA = \ interface.rng \ network.rng \ secret.rng \ + storageencryption.rng \ storagepool.rng \ storagevol.rng \ nodedev.rng \ diff --git a/docs/schemas/storageencryption.rng b/docs/schemas/storageencryption.rng new file mode 100644 index 0000000..8f9cd62 --- /dev/null +++ b/docs/schemas/storageencryption.rng @@ -0,0 +1,34 @@ +<!-- A Relax NG schema for the libvirt volume encryption XML format --> +<grammar xmlns="http://relaxng.org/ns/structure/1.0" + datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> + + <define name='encryption'> + <element name='encryption'> + <attribute name='format'> + <choice> + <value>default</value> + <value>qcow</value> + </choice> + </attribute> + <zeroOrMore> + <ref name='secret'/> + </zeroOrMore> + </element> + </define> + + <define name='secret'> + <element name='secret'> + <attribute name='type'> + <choice> + <value>passphrase</value> + </choice> + </attribute> + <optional> + <attribute name='uuid'> + <text/> + </attribute> + </optional> + </element> + </define> + +</grammar> diff --git a/docs/sitemap.html b/docs/sitemap.html index 901633d..24300d5 100644 --- a/docs/sitemap.html +++ b/docs/sitemap.html @@ -136,6 +136,9 @@ <a href="formatstorage.html">Storage</a> <span>The storage pool and volume XML format</span> </li><li> + <a href="formatstorageencryption.html">Storage Encryption</a> + <span>Storage volume encryption XML format</span> + </li><li> <a href="formatcaps.html">Capabilities</a> <span>The driver capabilities XML format</span> </li><li> diff --git a/docs/sitemap.html.in b/docs/sitemap.html.in index 2ed25c6..65de169 100644 --- a/docs/sitemap.html.in +++ b/docs/sitemap.html.in @@ -99,6 +99,10 @@ <span>The storage pool and volume XML format</span> </li> <li> + <a href="formatstorageencryption.html">Storage Encryption</a> + <span>Storage volume encryption XML format</span> + </li> + <li> <a href="formatcaps.html">Capabilities</a> <span>The driver capabilities XML format</span> </li> diff --git a/po/POTFILES.in b/po/POTFILES.in index e9d388a..ac3b2d6 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -41,6 +41,7 @@ src/storage_backend_logical.c src/storage_backend_scsi.c src/storage_conf.c src/storage_driver.c +src/storage_encryption.c src/test.c src/uml_conf.c src/uml_driver.c diff --git a/src/Makefile.am b/src/Makefile.am index ce33695..2c1c9b4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -52,6 +52,7 @@ UTIL_SOURCES = \ memory.c memory.h \ pci.c pci.h \ qparams.c qparams.h \ + storage_encryption.h storage_encryption.c \ threads.c threads.h \ threads-pthread.h \ threads-win32.h \ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index dd691be..c86e213 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -342,6 +342,11 @@ virStoragePartedFsTypeTypeToString; virStoragePoolObjLock; virStoragePoolObjUnlock; +virStorageEncryptionFree; +virStorageEncryptionDropSecrets; +virStorageEncryptionParseNode; +virStorageEncryptionFormat; + # threads.h virMutexInit; diff --git a/src/storage_encryption.c b/src/storage_encryption.c new file mode 100644 index 0000000..ccb29ed --- /dev/null +++ b/src/storage_encryption.c @@ -0,0 +1,241 @@ +/* + * storage_encryption.h: volume encryption information + * + * Copyright (C) 2009 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Red Hat Author: Miloslav Trmač <mitr@redhat.com> + */ + +#include <config.h> + +#include "internal.h" + +#include "base64.h" +#include "buf.h" +#include "memory.h" +#include "storage_conf.h" +#include "storage_encryption.h" +#include "util.h" +#include "xml.h" +#include "virterror_internal.h" + +#define VIR_FROM_THIS VIR_FROM_STORAGE + +VIR_ENUM_IMPL(virStorageEncryptionSecretType, + VIR_STORAGE_ENCRYPTION_SECRET_TYPE_LAST, "passphrase") + +VIR_ENUM_IMPL(virStorageEncryptionFormat, + VIR_STORAGE_ENCRYPTION_FORMAT_LAST, + "default", "qcow") + +static void +virStorageEncryptionSecretFree(virStorageEncryptionSecretPtr secret) +{ + if (!secret) + return; + VIR_FREE(secret->uuid); + VIR_FREE(secret); +} + +void +virStorageEncryptionFree(virStorageEncryptionPtr enc) +{ + size_t i; + + if (!enc) + return; + + for (i = 0; i < enc->nsecrets; i++) + virStorageEncryptionSecretFree(enc->secrets[i]); + VIR_FREE(enc->secrets); + VIR_FREE(enc); +} + +static virStorageEncryptionSecretPtr +virStorageEncryptionSecretParse(virConnectPtr conn, xmlXPathContextPtr ctxt, + xmlNodePtr node) +{ + xmlNodePtr old_node; + virStorageEncryptionSecretPtr ret; + char *type_str; + int type; + + if (VIR_ALLOC(ret) < 0) { + virReportOOMError(conn); + return NULL; + } + + old_node = ctxt->node; + ctxt->node = node; + + type_str = virXPathString(conn, "string(./@type)", ctxt); + if (type_str == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "%s", + _("unknown volume encryption secret type")); + goto cleanup; + } + type = virStorageEncryptionSecretTypeTypeFromString(type_str); + if (type < 0) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("unknown volume encryption secret type %s"), + type_str); + VIR_FREE(type_str); + goto cleanup; + } + VIR_FREE(type_str); + ret->type = type; + + ret->uuid = virXPathString(conn, "string(./@uuid)", ctxt); + ctxt->node = old_node; + return ret; + + cleanup: + virStorageEncryptionSecretFree(ret); + ctxt->node = old_node; + return NULL; +} + +static virStorageEncryptionPtr +virStorageEncryptionParseXML(virConnectPtr conn, xmlXPathContextPtr ctxt) +{ + xmlNodePtr *nodes = NULL; + virStorageEncryptionPtr ret; + char *format_str; + int format, i, n; + + if (VIR_ALLOC(ret) < 0) { + virReportOOMError(conn); + return NULL; + } + + format_str = virXPathString(conn, "string(./@format)", ctxt); + if (format_str == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "%s", + _("unknown volume encryption format")); + goto cleanup; + } + format = virStorageEncryptionFormatTypeFromString(format_str); + if (format < 0) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("unknown volume encryption format type %s"), + format_str); + VIR_FREE(format_str); + goto cleanup; + } + VIR_FREE(format_str); + ret->format = format; + + n = virXPathNodeSet(conn, "./secret", ctxt, &nodes); + if (n < 0){ + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot extract volume encryption secrets")); + goto cleanup; + } + if (n != 0 && VIR_ALLOC_N(ret->secrets, n) < 0) { + virReportOOMError(conn); + goto cleanup; + } + ret->nsecrets = n; + for (i = 0; i < n; i++) { + ret->secrets[i] = virStorageEncryptionSecretParse(conn, ctxt, nodes[i]); + if (ret->secrets[i] == NULL) + goto cleanup; + } + VIR_FREE(nodes); + + return ret; + + cleanup: + VIR_FREE(nodes); + virStorageEncryptionFree(ret); + return NULL; +} + +virStorageEncryptionPtr +virStorageEncryptionParseNode(virConnectPtr conn, + xmlDocPtr xml, xmlNodePtr root) +{ + xmlXPathContextPtr ctxt = NULL; + virStorageEncryptionPtr enc = NULL; + + if (STRNEQ((const char *) root->name, "encryption")) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + "%s", _("unknown root element for volume " + "encryption information")); + goto cleanup; + } + + ctxt = xmlXPathNewContext(xml); + if (ctxt == NULL) { + virReportOOMError(conn); + goto cleanup; + } + + ctxt->node = root; + enc = virStorageEncryptionParseXML(conn, ctxt); + + cleanup: + xmlXPathFreeContext(ctxt); + return enc; +} + +static int +virStorageEncryptionSecretFormat(virConnectPtr conn, + virBufferPtr buf, + virStorageEncryptionSecretPtr secret) +{ + const char *type; + + type = virStorageEncryptionSecretTypeTypeToString(secret->type); + if (!type) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("unexpected volume encryption secret type")); + return -1; + } + + virBufferVSprintf(buf, " <secret type='%s'", type); + if (secret->uuid != NULL) + virBufferEscapeString(buf, " uuid='%s'", secret->uuid); + virBufferAddLit(buf, "/>\n"); + return 0; +} + +int +virStorageEncryptionFormat(virConnectPtr conn, + virBufferPtr buf, + virStorageEncryptionPtr enc) +{ + const char *format; + size_t i; + + format = virStorageEncryptionFormatTypeToString(enc->format); + if (!format) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("unexpected encryption format")); + return -1; + } + virBufferVSprintf(buf, " <encryption format='%s'>\n", format); + + for (i = 0; i < enc->nsecrets; i++) { + if (virStorageEncryptionSecretFormat(conn, buf, enc->secrets[i]) < 0) + return -1; + } + + virBufferAddLit(buf, " </encryption>\n"); + + return 0; +} diff --git a/src/storage_encryption.h b/src/storage_encryption.h new file mode 100644 index 0000000..0e377cb --- /dev/null +++ b/src/storage_encryption.h @@ -0,0 +1,72 @@ +/* + * storage_encryption.h: volume encryption information + * + * Copyright (C) 2009 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Red Hat Author: Miloslav Trmač <mitr@redhat.com> + */ + +#ifndef __VIR_STORAGE_ENCRYPTION_H__ +#define __VIR_STORAGE_ENCRYPTION_H__ + +#include "internal.h" +#include "buf.h" +#include "util.h" + +#include <stdbool.h> +#include <libxml/tree.h> + +enum virStorageEncryptionSecretType { + VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE = 0, + + VIR_STORAGE_ENCRYPTION_SECRET_TYPE_LAST +}; +VIR_ENUM_DECL(virStorageEncryptionSecretType) + +typedef struct _virStorageEncryptionSecret virStorageEncryptionSecret; +typedef virStorageEncryptionSecret *virStorageEncryptionSecretPtr; +struct _virStorageEncryptionSecret { + int type; /* enum virStorageEncryptionSecretType */ + char *uuid; +}; + +enum virStorageEncryptionFormat { + /* "default" is only valid for volume creation */ + VIR_STORAGE_ENCRYPTION_FORMAT_DEFAULT = 0, + VIR_STORAGE_ENCRYPTION_FORMAT_QCOW, /* Both qcow and qcow2 */ + + VIR_STORAGE_ENCRYPTION_FORMAT_LAST, +}; +VIR_ENUM_DECL(virStorageEncryptionFormat) + +typedef struct _virStorageEncryption virStorageEncryption; +typedef virStorageEncryption *virStorageEncryptionPtr; +struct _virStorageEncryption { + int format; /* enum virStorageEncryptionFormat */ + + size_t nsecrets; + virStorageEncryptionSecretPtr *secrets; +}; + +void virStorageEncryptionFree(virStorageEncryptionPtr enc); +virStorageEncryptionPtr virStorageEncryptionParseNode(virConnectPtr conn, + xmlDocPtr xml, + xmlNodePtr root); +int virStorageEncryptionFormat(virConnectPtr conn, virBufferPtr buf, + virStorageEncryptionPtr enc); + +#endif /* __VIR_STORAGE_ENCRYPTION_H__ */ -- 1.6.2.5

The XML allows <encryption format='unencrypted'/>, this implementation canonicalizes the internal representation so that "vol->encryption" is non-NULL iff the volume is encrypted. Note that partial encryption information (e.g. specifying an encryption format, but not the key/passphrase) is valid, libvirt will automatically choose value for the missing information during volume creation. The user can read the volume XML, and use the unmodified <encryption> tag in future operations (without having to be able to understand) its contents. Changes since the second submission: - Mark <encryption> as <optional> in the schema - Drop <encryption format='unencrypted'/> - s/secret_id/uuid/g --- docs/formatstorage.html | 6 ++++++ docs/formatstorage.html.in | 8 ++++++++ docs/schemas/storagevol.rng | 5 +++++ src/storage_conf.c | 15 +++++++++++++++ src/storage_conf.h | 3 +++ tests/storagevolschemadata/vol-qcow2.xml | 3 +++ 6 files changed, 40 insertions(+), 0 deletions(-) diff --git a/docs/formatstorage.html b/docs/formatstorage.html index 8c16a0f..cb95263 100644 --- a/docs/formatstorage.html +++ b/docs/formatstorage.html @@ -252,6 +252,9 @@ <mode>0744</mode> <label>virt_image_t</label> </permissions> + <encryption type='...'> + ... + </encryption> </target> </pool></pre> <dl><dt><code>path</code></dt><dd>Provides the location at which the pool will be mapped into @@ -274,6 +277,9 @@ element contains the numeric group ID. The <code>label</code> element contains the MAC (eg SELinux) label string. <span class="since">Since 0.4.1</span> + </dd><dt><code>encryption</code></dt><dd>If present, specifies how the volume is encrypted. See + the <a href="formatstorageencryption.html">Storage Encryption</a> page + for more information. </dd></dl> <h3> <a name="StoragePoolExtents" id="StoragePoolExtents">Device extents</a> diff --git a/docs/formatstorage.html.in b/docs/formatstorage.html.in index 4878d72..3ed88a2 100644 --- a/docs/formatstorage.html.in +++ b/docs/formatstorage.html.in @@ -124,6 +124,9 @@ <mode>0744</mode> <label>virt_image_t</label> </permissions> + <encryption type='...'> + ... + </encryption> </target> </pool></pre> @@ -152,6 +155,11 @@ contains the MAC (eg SELinux) label string. <span class="since">Since 0.4.1</span> </dd> + <dt><code>encryption</code></dt> + <dd>If present, specifies how the volume is encrypted. See + the <a href="formatstorageencryption.html">Storage Encryption</a> page + for more information. + </dd> </dl> <h3><a name="StoragePoolExtents">Device extents</a></h3> diff --git a/docs/schemas/storagevol.rng b/docs/schemas/storagevol.rng index 5b0b038..00b70f6 100644 --- a/docs/schemas/storagevol.rng +++ b/docs/schemas/storagevol.rng @@ -5,6 +5,8 @@ <ref name='vol'/> </start> + <include href='storageencryption.rng'/> + <define name='vol'> <element name='volume'> @@ -73,6 +75,9 @@ </optional> <ref name='format'/> <ref name='permissions'/> + <optional> + <ref name='encryption'/> + </optional> </element> </define> diff --git a/src/storage_conf.c b/src/storage_conf.c index 245b2d0..c446069 100644 --- a/src/storage_conf.c +++ b/src/storage_conf.c @@ -260,8 +260,10 @@ virStorageVolDefFree(virStorageVolDefPtr def) { VIR_FREE(def->target.path); VIR_FREE(def->target.perms.label); + virStorageEncryptionFree(def->target.encryption); VIR_FREE(def->backingStore.path); VIR_FREE(def->backingStore.perms.label); + virStorageEncryptionFree(def->backingStore.encryption); VIR_FREE(def); } @@ -955,6 +957,7 @@ virStorageVolDefParseXML(virConnectPtr conn, char *allocation = NULL; char *capacity = NULL; char *unit = NULL; + xmlNodePtr node; options = virStorageVolOptionsForPoolType(pool->type); if (options == NULL) @@ -1019,6 +1022,14 @@ virStorageVolDefParseXML(virConnectPtr conn, "./target/permissions", 0600) < 0) goto cleanup; + node = virXPathNode(conn, "./target/encryption", ctxt); + if (node != NULL) { + ret->target.encryption = virStorageEncryptionParseNode(conn, ctxt->doc, + node); + if (ret->target.encryption == NULL) + goto cleanup; + } + ret->backingStore.path = virXPathString(conn, "string(./backingStore/path)", ctxt); @@ -1189,6 +1200,10 @@ virStorageVolTargetDefFormat(virConnectPtr conn, virBufferAddLit(buf," </permissions>\n"); + if (def->encryption != NULL && + virStorageEncryptionFormat(conn, buf, def->encryption) < 0) + return -1; + virBufferVSprintf(buf, " </%s>\n", type); return 0; diff --git a/src/storage_conf.h b/src/storage_conf.h index a6c3650..2fa14e9 100644 --- a/src/storage_conf.h +++ b/src/storage_conf.h @@ -26,6 +26,7 @@ #include "internal.h" #include "util.h" +#include "storage_encryption.h" #include "threads.h" #include <libxml/tree.h> @@ -77,6 +78,8 @@ struct _virStorageVolTarget { int format; virStoragePerms perms; int type; /* only used by disk backend for partition type */ + /* Currently used only in virStorageVolDef.target, not in .backingstore. */ + virStorageEncryptionPtr encryption; }; diff --git a/tests/storagevolschemadata/vol-qcow2.xml b/tests/storagevolschemadata/vol-qcow2.xml index c1cf02f..2a13cd1 100644 --- a/tests/storagevolschemadata/vol-qcow2.xml +++ b/tests/storagevolschemadata/vol-qcow2.xml @@ -14,6 +14,9 @@ <group>0</group> <label>unconfined_u:object_r:virt_image_t:s0</label> </permissions> + <encryption format='qcow'> + <secret type='passphrase' uuid='e78d4b51-a2af-485f-b0f5-afca709a80f4'/> + </encryption> </target> <backingStore> <path>/var/lib/libvirt/images/BaseDemo.img</path> -- 1.6.2.5

(The implementation is not very generic, but that can be very easily rectified if/when new encryption formats appear.) --- src/storage_backend_fs.c | 61 +++++++++++++++++++++++++++++++++++---------- 1 files changed, 47 insertions(+), 14 deletions(-) diff --git a/src/storage_backend_fs.c b/src/storage_backend_fs.c index ca6d329..5568b20 100644 --- a/src/storage_backend_fs.c +++ b/src/storage_backend_fs.c @@ -26,6 +26,7 @@ #include <sys/statvfs.h> #include <sys/types.h> #include <sys/stat.h> +#include <stdbool.h> #include <stdio.h> #include <dirent.h> #include <errno.h> @@ -81,6 +82,9 @@ struct FileTypeInfo { /* Store a COW base image path (possibly relative), * or NULL if there is no COW base image, to RES; * return BACKING_STORE_* */ + int qcowCryptOffset; /* Byte offset from start of file + * where to find encryption mode, + * -1 if encryption is not used */ int (*getBackingStore)(virConnectPtr conn, char **res, const unsigned char *buf, size_t buf_size); }; @@ -89,54 +93,54 @@ struct FileTypeInfo const fileTypeInfo[] = { /* XXX Untested { VIR_STORAGE_VOL_FILE_BOCHS, "Bochs Virtual HD Image", NULL, LV_LITTLE_ENDIAN, 64, 0x20000, - 32+16+16+4+4+4+4+4, 8, 1, NULL },*/ + 32+16+16+4+4+4+4+4, 8, 1, -1, NULL },*/ /* CLoop */ /* XXX Untested { VIR_STORAGE_VOL_CLOOP, "#!/bin/sh\n#V2.0 Format\nmodprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n", NULL, LV_LITTLE_ENDIAN, -1, 0, - -1, 0, 0, NULL }, */ + -1, 0, 0, -1, NULL }, */ /* Cow */ { VIR_STORAGE_VOL_FILE_COW, "OOOM", NULL, LV_BIG_ENDIAN, 4, 2, - 4+4+1024+4, 8, 1, cowGetBackingStore }, + 4+4+1024+4, 8, 1, -1, cowGetBackingStore }, /* DMG */ /* XXX QEMU says there's no magic for dmg, but we should check... */ { VIR_STORAGE_VOL_FILE_DMG, NULL, ".dmg", 0, -1, 0, - -1, 0, 0, NULL }, + -1, 0, 0, -1, NULL }, /* XXX there's probably some magic for iso we can validate too... */ { VIR_STORAGE_VOL_FILE_ISO, NULL, ".iso", 0, -1, 0, - -1, 0, 0, NULL }, + -1, 0, 0, -1, NULL }, /* Parallels */ /* XXX Untested { VIR_STORAGE_VOL_FILE_PARALLELS, "WithoutFreeSpace", NULL, LV_LITTLE_ENDIAN, 16, 2, - 16+4+4+4+4, 4, 512, NULL }, + 16+4+4+4+4, 4, 512, -1, NULL }, */ /* QCow */ { VIR_STORAGE_VOL_FILE_QCOW, "QFI", NULL, LV_BIG_ENDIAN, 4, 1, - 4+4+8+4+4, 8, 1, qcowXGetBackingStore }, + 4+4+8+4+4, 8, 1, 4+4+8+4+4+8+1+1+2, qcowXGetBackingStore }, /* QCow 2 */ { VIR_STORAGE_VOL_FILE_QCOW2, "QFI", NULL, LV_BIG_ENDIAN, 4, 2, - 4+4+8+4+4, 8, 1, qcowXGetBackingStore }, + 4+4+8+4+4, 8, 1, 4+4+8+4+4+8, qcowXGetBackingStore }, /* VMDK 3 */ /* XXX Untested { VIR_STORAGE_VOL_FILE_VMDK, "COWD", NULL, LV_LITTLE_ENDIAN, 4, 1, - 4+4+4, 4, 512, NULL }, + 4+4+4, 4, 512, -1, NULL }, */ /* VMDK 4 */ { VIR_STORAGE_VOL_FILE_VMDK, "KDMV", NULL, LV_LITTLE_ENDIAN, 4, 1, - 4+4+4, 8, 512, vmdk4GetBackingStore }, + 4+4+4, 8, 512, -1, vmdk4GetBackingStore }, /* Connectix / VirtualPC */ /* XXX Untested { VIR_STORAGE_VOL_FILE_VPC, "conectix", NULL, LV_BIG_ENDIAN, -1, 0, - -1, 0, 0, NULL}, + -1, 0, 0, -1, NULL}, */ }; @@ -282,13 +286,16 @@ static int virStorageBackendProbeTarget(virConnectPtr conn, virStorageVolTargetPtr target, char **backingStore, unsigned long long *allocation, - unsigned long long *capacity) { + unsigned long long *capacity, + virStorageEncryptionPtr *encryption) { int fd; unsigned char head[20*512]; /* vmdk4GetBackingStore needs this much. */ int len, i, ret; if (backingStore) *backingStore = NULL; + if (encryption) + *encryption = NULL; if ((fd = open(target->path, O_RDONLY)) < 0) { virReportSystemError(conn, errno, @@ -317,6 +324,8 @@ static int virStorageBackendProbeTarget(virConnectPtr conn, /* First check file magic */ for (i = 0 ; i < ARRAY_CARDINALITY(fileTypeInfo) ; i++) { int mlen; + bool encrypted_qcow = false; + if (fileTypeInfo[i].magic == NULL) continue; @@ -375,6 +384,16 @@ static int virStorageBackendProbeTarget(virConnectPtr conn, *capacity *= fileTypeInfo[i].sizeMultiplier; } + if (fileTypeInfo[i].qcowCryptOffset != -1) { + int crypt_format; + + crypt_format = (head[fileTypeInfo[i].qcowCryptOffset] << 24) | + (head[fileTypeInfo[i].qcowCryptOffset+1] << 16) | + (head[fileTypeInfo[i].qcowCryptOffset+2] << 8) | + head[fileTypeInfo[i].qcowCryptOffset+3]; + encrypted_qcow = crypt_format != 0; + } + /* Validation passed, we know the file format now */ target->format = fileTypeInfo[i].type; if (fileTypeInfo[i].getBackingStore != NULL && backingStore) { @@ -400,6 +419,18 @@ static int virStorageBackendProbeTarget(virConnectPtr conn, } } } + if (encryption != NULL && encrypted_qcow) { + virStorageEncryptionPtr enc; + + if (VIR_ALLOC(enc) < 0) { + virReportOOMError(conn); + if (backingStore) + VIR_FREE(*backingStore); + return -1; + } + enc->format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW; + *encryption = enc; + } return 0; } @@ -868,7 +899,8 @@ virStorageBackendFileSystemRefresh(virConnectPtr conn, &vol->target, &backingStore, &vol->allocation, - &vol->capacity) < 0)) { + &vol->capacity, + &vol->target.encryption) < 0)) { if (ret == -1) goto cleanup; else { @@ -908,7 +940,8 @@ virStorageBackendFileSystemRefresh(virConnectPtr conn, if ((ret = virStorageBackendProbeTarget(conn, &vol->backingStore, - NULL, NULL, NULL)) < 0) { + NULL, NULL, NULL, + NULL)) < 0) { if (ret == -1) goto cleanup; else { -- 1.6.2.5

Supports only virStorageVolCreateXML, not virStorageVolCreateXMLFrom. Curiously, qemu-img does not need the passphrase for anything to create an encrypted volume. This implementation thus does not need to touch any secrets to work with cooperating clients. More generic passphrase handling is added in the next patch. --- src/storage_backend.c | 47 +++++++++++++++++++++++++++++++++++++++- src/storage_backend_disk.c | 7 ++++++ src/storage_backend_fs.c | 7 ++++++ src/storage_backend_logical.c | 7 ++++++ 4 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/storage_backend.c b/src/storage_backend.c index 8824218..c818142 100644 --- a/src/storage_backend.c +++ b/src/storage_backend.c @@ -246,6 +246,13 @@ virStorageBackendCreateRaw(virConnectPtr conn, unsigned long long remain; char *buf = NULL; + if (vol->target.encryption != NULL) { + virStorageReportError(conn, VIR_ERR_NO_SUPPORT, + "%s", _("storage pool does not support encrypted " + "volumes")); + return -1; + } + if ((fd = open(vol->target.path, O_RDWR | O_CREAT | O_EXCL, vol->target.perms.mode)) < 0) { virReportSystemError(conn, errno, @@ -346,15 +353,17 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, NULL; const char **imgargv; + /* The extra NULL field is for indicating encryption (-e). */ const char *imgargvnormal[] = { NULL, "create", "-f", type, vol->target.path, size, NULL, + NULL }; /* Extra NULL fields are for including "backingType" when using - * kvm-img. It's -F backingType + * kvm-img (-F backingType), and for indicating encryption (-e). */ const char *imgargvbacking[] = { NULL, "create", @@ -364,6 +373,7 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, size, NULL, NULL, + NULL, NULL }; const char *convargv[] = { @@ -417,6 +427,28 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, } } + if (vol->target.encryption != NULL) { + if (vol->target.format != VIR_STORAGE_VOL_FILE_QCOW && + vol->target.format != VIR_STORAGE_VOL_FILE_QCOW2) { + virStorageReportError(conn, VIR_ERR_NO_SUPPORT, + _("qcow volume encryption unsupported with " + "volume format %s"), type); + return -1; + } + if (vol->target.encryption->format != + VIR_STORAGE_ENCRYPTION_FORMAT_QCOW) { + virStorageReportError(conn, VIR_ERR_NO_SUPPORT, + _("unsupported volume encryption format %d"), + vol->target.encryption->format); + return -1; + } + if (vol->target.encryption->nsecrets > 1) { + virStorageReportError(conn, VIR_ERR_INVALID_STORAGE_VOL, + _("too many secrets for qcow encryption")); + return -1; + } + } + if ((create_tool = virFindFileInPath("kvm-img")) != NULL) use_kvmimg = 1; else if ((create_tool = virFindFileInPath("qemu-img")) != NULL) @@ -437,11 +469,16 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, imgargvbacking[7] = backingType; imgargvbacking[8] = vol->target.path; imgargvbacking[9] = size; - } + if (vol->target.encryption != NULL) + imgargvbacking[10] = "-e"; + } else if (vol->target.encryption != NULL) + imgargvbacking[8] = "-e"; imgargv = imgargvbacking; } else { imgargvnormal[0] = create_tool; imgargv = imgargvnormal; + if (vol->target.encryption != NULL) + imgargv[6] = "-e"; } @@ -489,6 +526,12 @@ virStorageBackendCreateQcowCreate(virConnectPtr conn, "qcow-create")); return -1; } + if (vol->target.encryption != NULL) { + virStorageReportError(conn, VIR_ERR_NO_SUPPORT, + "%s", _("encrypted volumes not supported with " + "qcow-create")); + return -1; + } /* Size in MB - yes different units to qemu-img :-( */ snprintf(size, sizeof(size), "%llu", vol->capacity/1024/1024); diff --git a/src/storage_backend_disk.c b/src/storage_backend_disk.c index ae2acae..6fdb566 100644 --- a/src/storage_backend_disk.c +++ b/src/storage_backend_disk.c @@ -557,6 +557,13 @@ virStorageBackendDiskCreateVol(virConnectPtr conn, NULL }; + if (vol->target.encryption != NULL) { + virStorageReportError(conn, VIR_ERR_NO_SUPPORT, + "%s", _("storage pool does not support encrypted " + "volumes")); + return -1; + } + if (virStorageBackendDiskPartFormat(conn, pool, vol, partFormat) != 0) { return -1; } diff --git a/src/storage_backend_fs.c b/src/storage_backend_fs.c index 5568b20..65b656d 100644 --- a/src/storage_backend_fs.c +++ b/src/storage_backend_fs.c @@ -1102,6 +1102,13 @@ _virStorageBackendFileSystemVolBuild(virConnectPtr conn, int tool_type; if (inputvol) { + if (vol->target.encryption != NULL) { + virStorageReportError(conn, VIR_ERR_NO_SUPPORT, + "%s", _("storage pool does not support " + "building encrypted volumes from " + "other volumes")); + return -1; + } create_func = virStorageBackendGetBuildVolFromFunction(conn, vol, inputvol); if (!create_func) diff --git a/src/storage_backend_logical.c b/src/storage_backend_logical.c index 6c123ae..bc40dd7 100644 --- a/src/storage_backend_logical.c +++ b/src/storage_backend_logical.c @@ -581,6 +581,13 @@ virStorageBackendLogicalCreateVol(virConnectPtr conn, }; const char **cmdargv = cmdargvnew; + if (vol->target.encryption != NULL) { + virStorageReportError(conn, VIR_ERR_NO_SUPPORT, + "%s", _("storage pool does not support encrypted " + "volumes")); + return -1; + } + if (vol->backingStore.path) { cmdargv = cmdargvsnap; } -- 1.6.2.5

If the <encryption format='qcow'> element does not specify a secret during volume creation, generate a suitable secret and add it to the <encryption> tag. The caller can view the updated <encryption> tag using virStorageVolGetXMLDesc(). Similarly, when <encryption format='default'/> is specified while creating a qcow or qcow2-formatted volume, change the format to "qcow" and generate a secret as described above. Changes since the second submission: - Update for new internal API - s/secret_id/uuid/g --- src/storage_backend.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 124 insertions(+), 3 deletions(-) diff --git a/src/storage_backend.c b/src/storage_backend.c index c818142..867c9b0 100644 --- a/src/storage_backend.c +++ b/src/storage_backend.c @@ -43,6 +43,7 @@ #include <selinux/selinux.h> #endif +#include "datatypes.h" #include "virterror_internal.h" #include "util.h" #include "memory.h" @@ -331,6 +332,118 @@ cleanup: } static int +virStorageGenerateQcowEncryption(virConnectPtr conn, + virStorageVolDefPtr vol) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + virStorageEncryptionPtr enc; + virStorageEncryptionSecretPtr enc_secret = NULL; + virSecretPtr secret = NULL; + char *uuid = NULL, *xml; + unsigned char value[16]; + int ret = -1, fd = -1; + size_t i; + + if (conn->secretDriver == NULL || conn->secretDriver->defineXML == NULL || + conn->secretDriver->setValue == NULL) { + virStorageReportError(conn, VIR_ERR_NO_SUPPORT, "%s", + _("secret storage not supported")); + goto cleanup; + } + + enc = vol->target.encryption; + if (enc->nsecrets != 0) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("secrets already defined")); + goto cleanup; + } + + if (VIR_ALLOC(enc_secret) < 0 || VIR_REALLOC_N(enc->secrets, 1) < 0) { + virReportOOMError(conn); + goto cleanup; + } + + virBufferAddLit(&buf, "<secret ephemeral='no' private='no'>"); + /* <uuid/> is chosen by the secret driver */ + virBufferEscapeString(&buf, + "<description>qcow passphrase for %s</description>", + vol->target.path); + virBufferEscapeString(&buf, "<volume>%s</volume>", vol->target.path); + virBufferAddLit(&buf, "</secret>"); + if (virBufferError(&buf)) { + virReportOOMError(conn); + goto cleanup; + } + xml = virBufferContentAndReset(&buf); + secret = conn->secretDriver->defineXML(conn, xml); + if (secret == NULL) { + VIR_FREE(xml); + goto cleanup; + } + VIR_FREE(xml); + + uuid = strdup(secret->uuid); + if (uuid == NULL) { + virReportOOMError(conn); + goto cleanup; + } + + /* A qcow passphrase is up to 16 bytes, with any data following a NUL + ignored. Prohibit control and non-ASCII characters to avoid possible + unpleasant surprises with the qemu monitor input mechanism. */ + fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot open /dev/urandom")); + goto cleanup; + } + i = 0; + while (i < sizeof (value)) { + ssize_t r; + + while ((r = read(fd, value + i, 1)) == -1 && errno == EINTR) + ; + if (r <= 0) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot read from /dev/urandom")); + goto cleanup; + } + if (value[i] >= 0x20 && value[i] <= 0x7E) + i++; /* Got an acceptable character */ + } + close(fd); + fd = -1; + + if (conn->secretDriver->setValue(secret, value, sizeof(value)) < 0) + goto cleanup; + secret = NULL; + + enc_secret->type = VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE; + enc_secret->uuid = uuid; + uuid = NULL; + enc->format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW; + enc->secrets[0] = enc_secret; /* Space for secrets[0] allocated above */ + enc_secret = NULL; + enc->nsecrets = 1; + + ret = 0; + +cleanup: + if (fd != -1) + close(fd); + VIR_FREE(uuid); + if (secret != NULL) { + if (conn->secretDriver->undefine != NULL) + conn->secretDriver->undefine(secret); + virSecretFree(secret); + } + xml = virBufferContentAndReset(&buf); + VIR_FREE(xml); + VIR_FREE(enc_secret); + return ret; +} + +static int virStorageBackendCreateQemuImg(virConnectPtr conn, virStorageVolDefPtr vol, virStorageVolDefPtr inputvol, @@ -428,6 +541,8 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, } if (vol->target.encryption != NULL) { + virStorageEncryptionPtr enc; + if (vol->target.format != VIR_STORAGE_VOL_FILE_QCOW && vol->target.format != VIR_STORAGE_VOL_FILE_QCOW2) { virStorageReportError(conn, VIR_ERR_NO_SUPPORT, @@ -435,18 +550,24 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, "volume format %s"), type); return -1; } - if (vol->target.encryption->format != - VIR_STORAGE_ENCRYPTION_FORMAT_QCOW) { + enc = vol->target.encryption; + if (enc->format != VIR_STORAGE_ENCRYPTION_FORMAT_QCOW && + enc->format != VIR_STORAGE_ENCRYPTION_FORMAT_DEFAULT) { virStorageReportError(conn, VIR_ERR_NO_SUPPORT, _("unsupported volume encryption format %d"), vol->target.encryption->format); return -1; } - if (vol->target.encryption->nsecrets > 1) { + if (enc->nsecrets > 1) { virStorageReportError(conn, VIR_ERR_INVALID_STORAGE_VOL, _("too many secrets for qcow encryption")); return -1; } + if (enc->format == VIR_STORAGE_ENCRYPTION_FORMAT_DEFAULT || + enc->nsecrets == 0) { + if (virStorageGenerateQcowEncryption(conn, vol) < 0) + return -1; + } } if ((create_tool = virFindFileInPath("kvm-img")) != NULL) -- 1.6.2.5

The XML allows <encryption format='unencrypted'/>, this implementation canonicalizes the internal representation so that "disk->encryption" is non-NULL iff encryption information is available. A domain with partial encryption information can be defined, completeness of the information is not verified. The domain won't start until the remaining information is added, of course. Changes since the second submission: - Mark <encryption> as <optional> in the schema - Drop <encryption format='unencrypted'/> --- docs/formatdomain.html | 6 ++++++ docs/formatdomain.html.in | 8 ++++++++ docs/schemas/domain.rng | 5 +++++ src/domain_conf.c | 14 ++++++++++++++ src/domain_conf.h | 2 ++ 5 files changed, 35 insertions(+), 0 deletions(-) diff --git a/docs/formatdomain.html b/docs/formatdomain.html index efba65a..3368ad5 100644 --- a/docs/formatdomain.html +++ b/docs/formatdomain.html @@ -453,6 +453,9 @@ <driver name="tap" type="aio"> <source file='/var/lib/xen/images/fv0'/> <target dev='hda' bus='ide'/> + <encryption type='...'> + ... + </encryption> </disk> ...</pre> <dl><dt><code>disk</code></dt><dd>The <code>disk</code> element is the main container for describing @@ -478,6 +481,9 @@ <code>driver</code> element allows them to be selected. The <code>name</code> attribute is the primary backend driver name, while the optional <code>type</code> attribute provides the sub-type. <span class="since">Since 0.1.8</span> + </dd><dt><code>encryption</code></dt><dd>If present, specifies how the volume is encrypted. See + the <a href="formatstorageencryption.html">Storage Encryption</a> page + for more information. </dd></dl> <h4> <a name="elementsUSB" id="elementsUSB">USB and PCI devices</a> diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index eb12784..211f7ed 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -338,6 +338,9 @@ <driver name="tap" type="aio"> <source file='/var/lib/xen/images/fv0'/> <target dev='hda' bus='ide'/> + <encryption type='...'> + ... + </encryption> </disk> ...</pre> @@ -373,6 +376,11 @@ attribute is the primary backend driver name, while the optional <code>type</code> attribute provides the sub-type. <span class="since">Since 0.1.8</span> </dd> + <dt><code>encryption</code></dt> + <dd>If present, specifies how the volume is encrypted. See + the <a href="formatstorageencryption.html">Storage Encryption</a> page + for more information. + </dd> </dl> <h4><a name="elementsUSB">USB and PCI devices</a></h4> diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index f857301..df31f4a 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -4,6 +4,8 @@ <start> <ref name="domain"/> </start> + + <include href='storageencryption.rng'/> <!-- We handle only document defining a domain --> @@ -336,6 +338,9 @@ <empty/> </element> </optional> + <optional> + <ref name="encryption"/> + </optional> </define> <!-- A disk description can be either of type file or block diff --git a/src/domain_conf.c b/src/domain_conf.c index bad53f7..c5b9ae5 100644 --- a/src/domain_conf.c +++ b/src/domain_conf.c @@ -288,6 +288,7 @@ void virDomainDiskDefFree(virDomainDiskDefPtr def) VIR_FREE(def->dst); VIR_FREE(def->driverName); VIR_FREE(def->driverType); + virStorageEncryptionFree(def->encryption); VIR_FREE(def); } @@ -658,6 +659,7 @@ virDomainDiskDefParseXML(virConnectPtr conn, char *bus = NULL; char *cachetag = NULL; char *devaddr = NULL; + virStorageEncryptionPtr encryption = NULL; if (VIR_ALLOC(def) < 0) { virReportOOMError(conn); @@ -715,6 +717,12 @@ virDomainDiskDefParseXML(virConnectPtr conn, } else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) && xmlStrEqual(cur->name, BAD_CAST "state")) { devaddr = virXMLPropString(cur, "devaddr"); + } else if (encryption == NULL && + xmlStrEqual(cur->name, BAD_CAST "encryption")) { + encryption = virStorageEncryptionParseNode(conn, node->doc, + cur); + if (encryption == NULL) + goto error; } } cur = cur->next; @@ -833,6 +841,8 @@ virDomainDiskDefParseXML(virConnectPtr conn, driverName = NULL; def->driverType = driverType; driverType = NULL; + def->encryption = encryption; + encryption = NULL; cleanup: VIR_FREE(bus); @@ -844,6 +854,7 @@ cleanup: VIR_FREE(driverName); VIR_FREE(cachetag); VIR_FREE(devaddr); + virStorageEncryptionFree(encryption); return def; @@ -3516,6 +3527,9 @@ virDomainDiskDefFormat(virConnectPtr conn, virBufferAddLit(buf, " <readonly/>\n"); if (def->shared) virBufferAddLit(buf, " <shareable/>\n"); + if (def->encryption != NULL && + virStorageEncryptionFormat(conn, buf, def->encryption) < 0) + return -1; if (flags & VIR_DOMAIN_XML_INTERNAL_STATUS) { virBufferAddLit(buf, " <state"); diff --git a/src/domain_conf.h b/src/domain_conf.h index 44302be..e422f6f 100644 --- a/src/domain_conf.h +++ b/src/domain_conf.h @@ -30,6 +30,7 @@ #include "internal.h" #include "capabilities.h" +#include "storage_encryption.h" #include "util.h" #include "threads.h" @@ -117,6 +118,7 @@ struct _virDomainDiskDef { unsigned bus; unsigned slot; } pci_addr; + virStorageEncryptionPtr encryption; }; static inline int -- 1.6.2.5

The if ((nlptr...)) implicitly assumes commptr != NULL (and that "buf" starts with "cmd"). Make the assumption explicit, it will be broken in a future patch. --- src/qemu_driver.c | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/qemu_driver.c b/src/qemu_driver.c index 4b1aeea..68c2061 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -2482,10 +2482,11 @@ qemudMonitorCommandExtra(const virDomainObjPtr vm, * occurence, and inbetween the command and the newline starting * the response */ - if ((commptr = strstr(buf, cmd))) + if ((commptr = strstr(buf, cmd))) { memmove(buf, commptr, strlen(commptr)+1); - if ((nlptr = strchr(buf, '\n'))) - memmove(buf+strlen(cmd), nlptr, strlen(nlptr)+1); + if ((nlptr = strchr(buf, '\n'))) + memmove(buf+strlen(cmd), nlptr, strlen(nlptr)+1); + } break; } -- 1.6.2.5

Support arbitrary callbacks for "secondary prompts". Reimplement qemudMonitorCommandExtra using such a callback. --- src/qemu_driver.c | 84 +++++++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 72 insertions(+), 12 deletions(-) diff --git a/src/qemu_driver.c b/src/qemu_driver.c index 68c2061..adce809 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -88,6 +88,12 @@ static void qemuDriverUnlock(struct qemud_driver *driver) virMutexUnlock(&driver->lock); } +/* Return -1 for error, 0 for success */ +typedef int qemudMonitorExtraPromptHandler(const virDomainObjPtr vm, + const char *buf, + const char *prompt, + void *data); + static void qemuDomainEventFlush(int timer, void *opaque); static void qemuDomainEventQueue(struct qemud_driver *driver, virDomainEventPtr event); @@ -116,6 +122,13 @@ static int qemudMonitorCommandWithFd(const virDomainObjPtr vm, const char *cmd, int scm_fd, char **reply); +static int qemudMonitorCommandWithHandler(const virDomainObjPtr vm, + const char *cmd, + const char *extraPrompt, + qemudMonitorExtraPromptHandler extraHandler, + void *handlerData, + int scm_fd, + char **reply); static int qemudMonitorCommandExtra(const virDomainObjPtr vm, const char *cmd, const char *extra, @@ -2415,12 +2428,13 @@ out: } static int -qemudMonitorCommandExtra(const virDomainObjPtr vm, - const char *cmd, - const char *extra, - const char *extraPrompt, - int scm_fd, - char **reply) { +qemudMonitorCommandWithHandler(const virDomainObjPtr vm, + const char *cmd, + const char *extraPrompt, + qemudMonitorExtraPromptHandler extraHandler, + void *handlerData, + int scm_fd, + char **reply) { int size = 0; char *buf = NULL; @@ -2464,12 +2478,20 @@ qemudMonitorCommandExtra(const virDomainObjPtr vm, /* Look for QEMU prompt to indicate completion */ if (buf) { - if (extra) { - if (strstr(buf, extraPrompt) != NULL) { - if (qemudMonitorSend(vm, extra, -1) < 0) - return -1; - extra = NULL; - } + char *foundPrompt; + + if (extraPrompt && + (foundPrompt = strstr(buf, extraPrompt)) != NULL) { + char *promptEnd; + + if (extraHandler(vm, buf, foundPrompt, handlerData) < 0) + return -1; + /* Discard output so far, necessary to detect whether + extraPrompt appears again. We don't need the output between + original command and this prompt anyway. */ + promptEnd = foundPrompt + strlen(extraPrompt); + memmove(buf, promptEnd, strlen(promptEnd)+1); + size -= promptEnd - buf; } else if ((tmp = strstr(buf, QEMU_CMD_PROMPT)) != NULL) { char *commptr = NULL, *nlptr = NULL; /* Preserve the newline */ @@ -2507,6 +2529,44 @@ qemudMonitorCommandExtra(const virDomainObjPtr vm, return -1; } +struct extraHandlerData +{ + const char *reply; + bool first; +}; + +static int +qemudMonitorCommandSimpleExtraHandler(const virDomainObjPtr vm, + const char *buf ATTRIBUTE_UNUSED, + const char *prompt ATTRIBUTE_UNUSED, + void *data_) +{ + struct extraHandlerData *data = data_; + + if (!data->first) + return 0; + if (qemudMonitorSend(vm, data->reply, -1) < 0) + return -1; + data->first = false; + return 0; +} + +static int +qemudMonitorCommandExtra(const virDomainObjPtr vm, + const char *cmd, + const char *extra, + const char *extraPrompt, + int scm_fd, + char **reply) { + struct extraHandlerData data; + + data.reply = extra; + data.first = true; + return qemudMonitorCommandWithHandler(vm, cmd, extraPrompt, + qemudMonitorCommandSimpleExtraHandler, + &data, scm_fd, reply); +} + static int qemudMonitorCommandWithFd(const virDomainObjPtr vm, const char *cmd, -- 1.6.2.5

The interface allows qemudMonitorSendCont() to report errors that are not overridden by its callers. Also fix a potential infinite loop in qemuDomainCoreDump() if sending cont repeatedly fails. Changes since the second submission: - Handle one more, newly added, "cont" command --- src/qemu_driver.c | 89 +++++++++++++++++++++++++++++++---------------------- 1 files changed, 52 insertions(+), 37 deletions(-) diff --git a/src/qemu_driver.c b/src/qemu_driver.c index adce809..b1a1c6a 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -28,6 +28,7 @@ #include <dirent.h> #include <limits.h> #include <string.h> +#include <stdbool.h> #include <stdio.h> #include <strings.h> #include <stdarg.h> @@ -135,6 +136,9 @@ static int qemudMonitorCommandExtra(const virDomainObjPtr vm, const char *extraPrompt, int scm_fd, char **reply); +static int qemudMonitorSendCont(virConnectPtr conn, + const virDomainObjPtr vm, + bool *error_reported); static int qemudDomainSetMemoryBalloon(virConnectPtr conn, virDomainObjPtr vm, unsigned long newmem); @@ -1225,7 +1229,6 @@ static int qemudInitCpus(virConnectPtr conn, virDomainObjPtr vm, const char *migrateFrom) { - char *info = NULL; #if HAVE_SCHED_GETAFFINITY cpu_set_t mask; int i, maxcpu = QEMUD_CPUMASK_LEN; @@ -1260,13 +1263,15 @@ qemudInitCpus(virConnectPtr conn, #endif /* HAVE_SCHED_GETAFFINITY */ if (migrateFrom == NULL) { + bool error_reported; + /* Allow the CPUS to start executing */ - if (qemudMonitorCommand(vm, "cont", &info) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("resume operation failed")); + if (qemudMonitorSendCont(conn, vm, &error_reported) < 0) { + if (!error_reported) + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "%s", _("resume operation failed")); return -1; } - VIR_FREE(info); } return 0; @@ -2582,6 +2587,20 @@ qemudMonitorCommand(const virDomainObjPtr vm, return qemudMonitorCommandWithFd(vm, cmd, -1, reply); } +static int +qemudMonitorSendCont(virConnectPtr conn ATTRIBUTE_UNUSED, + const virDomainObjPtr vm, + bool *error_reported) { + char *reply; + + *error_reported = false; + if (qemudMonitorCommand(vm, "cont", &reply) < 0) + return -1; + qemudDebug ("%s: cont reply: %s", vm->def->name, info); + VIR_FREE(reply); + return 0; +} + static virDrvOpenStatus qemudOpen(virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) { @@ -3066,7 +3085,6 @@ cleanup: static int qemudDomainResume(virDomainPtr dom) { struct qemud_driver *driver = dom->conn->privateData; - char *info; virDomainObjPtr vm; int ret = -1; virDomainEventPtr event = NULL; @@ -3087,17 +3105,18 @@ static int qemudDomainResume(virDomainPtr dom) { goto cleanup; } if (vm->state == VIR_DOMAIN_PAUSED) { - if (qemudMonitorCommand(vm, "cont", &info) < 0) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("resume operation failed")); + bool error_reported; + + if (qemudMonitorSendCont(dom->conn, vm, &error_reported) < 0) { + if (!error_reported) + qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("resume operation failed")); goto cleanup; } vm->state = VIR_DOMAIN_RUNNING; - qemudDebug("Reply %s", info); event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_RESUMED, VIR_DOMAIN_EVENT_RESUMED_UNPAUSED); - VIR_FREE(info); } if (virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0) goto cleanup; @@ -3788,13 +3807,13 @@ cleanup: will support synchronous operations so we always get here after the migration is complete. */ if (resume && paused) { - if (qemudMonitorCommand(vm, "cont", &info) < 0) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("resuming after dump failed")); - goto cleanup; + bool error_reported; + + if (qemudMonitorSendCont(dom->conn, vm, &error_reported) < 0) { + if (!error_reported) + qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("resuming after dump failed")); } - DEBUG ("%s: cont reply: %s", vm->def->name, info); - VIR_FREE(info); } if (vm) virDomainObjUnlock(vm); @@ -4272,13 +4291,14 @@ static int qemudDomainRestore(virConnectPtr conn, /* If it was running before, resume it now. */ if (header.was_running) { - char *info; - if (qemudMonitorCommand(vm, "cont", &info) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("failed to resume domain")); + bool error_reported; + + if (qemudMonitorSendCont(conn, vm, &error_reported) < 0) { + if (!error_reported) + qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("failed to resume domain")); goto cleanup; } - VIR_FREE(info); vm->state = VIR_DOMAIN_RUNNING; virDomainSaveStatus(conn, driver->stateDir, vm); } @@ -6950,14 +6970,11 @@ qemudDomainMigratePerform (virDomainPtr dom, ret = 0; cleanup: - /* Note that we have to free info *first*, since we are re-using the - * variable below (and otherwise might cause a memory leak) - */ - VIR_FREE(info); - if (paused) { + bool error_reported; + /* we got here through some sort of failure; start the domain again */ - if (qemudMonitorCommand (vm, "cont", &info) < 0) { + if (qemudMonitorSendCont(dom->conn, vm, &error_reported) < 0) { /* Hm, we already know we are in error here. We don't want to * overwrite the previous error, though, so we just throw something * to the logs and hope for the best @@ -6965,16 +6982,13 @@ cleanup: VIR_ERROR(_("Failed to resume guest %s after failure\n"), vm->def->name); } - else { - DEBUG ("%s: cont reply: %s", vm->def->name, info); - VIR_FREE(info); - } event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_RESUMED, VIR_DOMAIN_EVENT_RESUMED_MIGRATED); } + VIR_FREE(info); if (vm) virDomainObjUnlock(vm); if (event) @@ -6997,7 +7011,6 @@ qemudDomainMigrateFinish2 (virConnectPtr dconn, virDomainObjPtr vm; virDomainPtr dom = NULL; virDomainEventPtr event = NULL; - char *info = NULL; qemuDriverLock(driver); vm = virDomainFindByName(&driver->domains, dname); @@ -7011,18 +7024,20 @@ qemudDomainMigrateFinish2 (virConnectPtr dconn, * object, but if no, clean up the empty qemu process. */ if (retcode == 0) { + bool error_reported; + dom = virGetDomain (dconn, vm->def->name, vm->def->uuid); /* run 'cont' on the destination, which allows migration on qemu * >= 0.10.6 to work properly. This isn't strictly necessary on * older qemu's, but it also doesn't hurt anything there */ - if (qemudMonitorCommand(vm, "cont", &info) < 0) { - qemudReportError(dconn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("resume operation failed")); + if (qemudMonitorSendCont(dconn, vm, &error_reported) < 0) { + if (!error_reported) + qemudReportError(dconn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "%s", _("resume operation failed")); goto cleanup; } - VIR_FREE(info); vm->state = VIR_DOMAIN_RUNNING; event = virDomainEventNewFromObj(vm, -- 1.6.2.5

Changes since the second submission: - Update for changed internal API - s/secret_id/uuid/g - Use "unsigned char *" for secret value --- src/qemu_driver.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 153 insertions(+), 8 deletions(-) diff --git a/src/qemu_driver.c b/src/qemu_driver.c index b1a1c6a..8404bc1 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -1284,12 +1284,6 @@ qemudInitPasswords(virConnectPtr conn, virDomainObjPtr vm) { char *info = NULL; - /* - * NB: Might have more passwords to set in the future. eg a qcow - * disk decryption password, but there's no monitor command - * for that yet... - */ - if ((vm->def->ngraphics == 1) && vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC && (vm->def->graphics[0]->data.vnc.passwd || driver->vncPassword)) { @@ -2587,14 +2581,165 @@ qemudMonitorCommand(const virDomainObjPtr vm, return qemudMonitorCommandWithFd(vm, cmd, -1, reply); } +static virStorageEncryptionPtr +findDomainDiskEncryption(virConnectPtr conn, virDomainObjPtr vm, + const char *path) +{ + bool seen_volume; + int i; + + seen_volume = false; + for (i = 0; i < vm->def->ndisks; i++) { + virDomainDiskDefPtr disk; + + disk = vm->def->disks[i]; + if (disk->src != NULL && STREQ(disk->src, path)) { + seen_volume = true; + if (disk->encryption != NULL) + return disk->encryption; + } + } + if (seen_volume) + qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN, + _("missing <encryption> for volume %s"), path); + else + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("unexpected passphrase request for volume %s"), + path); + return NULL; +} + +static char * +findVolumeQcowPassphrase(virConnectPtr conn, virDomainObjPtr vm, + const char *path, size_t *passphrase_len) +{ + virStorageEncryptionPtr enc; + virSecretPtr secret; + char *passphrase; + unsigned char *data; + size_t size; + + if (conn->secretDriver == NULL || + conn->secretDriver->lookupByUUIDString == NULL || + conn->secretDriver->getValue == NULL) { + qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SUPPORT, "%s", + _("secret storage not supported")); + return NULL; + } + + enc = findDomainDiskEncryption(conn, vm, path); + if (enc == NULL) + return NULL; + + if (enc->format != VIR_STORAGE_ENCRYPTION_FORMAT_QCOW || + enc->nsecrets != 1 || + enc->secrets[0]->type != + VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN, + _("invalid <encryption> for volume %s"), path); + return NULL; + } + + if (enc->secrets[0]->uuid == NULL) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN, + _("missing secret uuid for volume %s"), path); + return NULL; + } + secret = conn->secretDriver->lookupByUUIDString(conn, + enc->secrets[0]->uuid); + if (secret == NULL) + return NULL; + data = conn->secretDriver->getValue(secret, &size, true); + virUnrefSecret(secret); + if (data == NULL) + return NULL; + + if (memchr(data, '\0', size) != NULL) { + memset(data, 0, size); + VIR_FREE(data); + qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_SECRET, + _("format='qcow' passphrase for %s must not contain a " + "'\\0'"), path); + return NULL; + } + + if (VIR_ALLOC_N(passphrase, size + 1) < 0) { + memset(data, 0, size); + VIR_FREE(data); + virReportOOMError(conn); + return NULL; + } + memcpy(passphrase, data, size); + passphrase[size] = '\0'; + + memset(data, 0, size); + VIR_FREE(data); + + *passphrase_len = size; + return passphrase; +} + +struct sendVolumePassphraseState { + virConnectPtr conn; + bool *error_reported; +}; + +static int +qemudMonitorSendVolumePassphrase(const virDomainObjPtr vm, + const char *buf, + const char *prompt, + void *data) +{ + const struct sendVolumePassphraseState *state = data; + char *passphrase, *path; + const char *prompt_path; + size_t path_len, passphrase_len = 0; + int res; + + /* The complete prompt looks like this: + ide0-hd0 (/path/to/volume) is encrypted. + Password: + "prompt" starts with ") is encrypted". Extract /path/to/volume. */ + for (prompt_path = prompt; prompt_path > buf && prompt_path[-1] != '('; + prompt_path--) + ; + if (prompt_path == buf) + return -1; + path_len = prompt - prompt_path; + if (VIR_ALLOC_N(path, path_len + 1) < 0) + return -1; + memcpy(path, prompt_path, path_len); + path[path_len] = '\0'; + + passphrase = findVolumeQcowPassphrase(state->conn, vm, path, + &passphrase_len); + VIR_FREE(path); + if (passphrase == NULL) { + *state->error_reported = true; + return -1; + } + + res = qemudMonitorSend(vm, passphrase, -1); + + memset(passphrase, 0, passphrase_len); + VIR_FREE(passphrase); + + return res; +} + static int -qemudMonitorSendCont(virConnectPtr conn ATTRIBUTE_UNUSED, +qemudMonitorSendCont(virConnectPtr conn, const virDomainObjPtr vm, bool *error_reported) { + struct sendVolumePassphraseState state; char *reply; *error_reported = false; - if (qemudMonitorCommand(vm, "cont", &reply) < 0) + state.conn = conn; + state.error_reported = error_reported; + if (qemudMonitorCommandWithHandler(vm, "cont", ") is encrypted.", + qemudMonitorSendVolumePassphrase, + &state, -1, &reply) < 0) return -1; qemudDebug ("%s: cont reply: %s", vm->def->name, info); VIR_FREE(reply); -- 1.6.2.5
participants (4)
-
Daniel P. Berrange
-
Daniel Veillard
-
Miloslav Trmac
-
Miloslav Trmač