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

Hello, the following patches add full support for qcow/qcow2 volume encryption, assuming a client that supports it. (Main changes since the previous version: * Add "flags" argument to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretSetValue(), virSecretGetValue() * Various clean-ups and bug fixes in the local secret storage driver * Make the Python API more consistent with other objects 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 third submission: - Add "flags" parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. --- 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 | 38 +++++++++ include/libvirt/libvirt.h.in | 38 +++++++++ src/libvirt_public.syms | 16 ++++ 15 files changed, 390 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..1779b08 100644 --- a/include/libvirt/libvirt.h +++ b/include/libvirt/libvirt.h @@ -1448,6 +1448,44 @@ 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, + unsigned int flags); +char * virSecretGetUUIDString (virSecretPtr secret); +char * virSecretGetXMLDesc (virSecretPtr secret, + unsigned int flags); +int virSecretSetValue (virSecretPtr secret, + const unsigned char *value, + size_t value_size, + unsigned int flags); +unsigned char * virSecretGetValue (virSecretPtr secret, + size_t *value_size, + unsigned int flags); +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..8e26e48 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1448,6 +1448,44 @@ 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, + unsigned int flags); +char * virSecretGetUUIDString (virSecretPtr secret); +char * virSecretGetXMLDesc (virSecretPtr secret, + unsigned int flags); +int virSecretSetValue (virSecretPtr secret, + const unsigned char *value, + size_t value_size, + unsigned int flags); +unsigned char * virSecretGetValue (virSecretPtr secret, + size_t *value_size, + unsigned int flags); +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 Thu, Aug 20, 2009 at 08:17:59PM +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.
Changes since the third submission: - Add "flags" parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces.
ACK, this API is fine now. 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 Thu, Aug 20, 2009 at 08:17:59PM +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>
Following on with my comments fro the virsh patch later in this series, I reckon we ought to move the 'volume' element inside a 'usage' element eg, to look like <secret ephemeral='no' private='yes'> <uuid>b8eecf55-798e-4db7-b2dd-025b0cf08a36</uuid> <usage type='volume'> <volume path='/var/lib/libvirt/images/mail.img'/> </usage> <description>LUKS passphrase for our mail server</description> </secret> So, if we then allow the virSecret APIs to be used for things like the guest VNC server, we could have a nice variation such as <secret ephemeral='no' private='yes'> <uuid>b8eecf55-798e-4db7-b2dd-025b0cf08a36</uuid> <usage type='vnc'> <guest name='myguest'/> </usage> <description>LUKS passphrase for our mail server</description> </secret> and other variations for whatever we might need in the future. Regards, 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 third submission: - Add "flags" parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. - Fix a copy&pasted comment --- include/libvirt/virterror.h | 1 + src/datatypes.c | 155 +++++++++++++++++++++++++++++++++++++++++++ src/datatypes.h | 28 ++++++++ src/driver.h | 61 +++++++++++++++++ src/libvirt.c | 53 +++++++++++++++ src/libvirt_private.syms | 2 + src/virterror.c | 6 ++ 7 files changed, 306 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 d03a679..2e85196 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 secret object, this is just used by the secret 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); @@ -246,6 +270,8 @@ virUnrefConnect(virConnectPtr conn) { conn->storageDriver->close (conn); if (conn->deviceMonitor) conn->deviceMonitor->close (conn); + if (conn->secretDriver) + conn->secretDriver->close (conn); if (conn->driver) conn->driver->close (conn); @@ -1129,3 +1155,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..a6b8e01 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,63 @@ struct _virDeviceMonitor { virDrvNodeDeviceDestroy deviceDestroy; }; +typedef virSecretPtr + (*virDrvSecretLookupByUUIDString) (virConnectPtr conn, + const char *uuid); +typedef virSecretPtr + (*virDrvSecretDefineXML) (virConnectPtr conn, + const char *xml, + unsigned int flags); +typedef char * + (*virDrvSecretGetXMLDesc) (virSecretPtr secret, + unsigned int flags); +typedef int + (*virDrvSecretSetValue) (virSecretPtr secret, + const unsigned char *value, + size_t value_size, + unsigned int flags); +typedef unsigned char * + (*virDrvSecretGetValue) (virSecretPtr secret, + size_t *value_size, + bool libvirt_internal_call, + unsigned int flags); +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 +869,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 ca8e003..bea60f4 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: diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 2bf4e15..f2c0736 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 Thu, Aug 20, 2009 at 08:18:00PM +0200, Miloslav Trma?? wrote:
Adds a new driver type.
Changes since the third submission: - Add "flags" parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. - Fix a copy&pasted comment --- include/libvirt/virterror.h | 1 + src/datatypes.c | 155 +++++++++++++++++++++++++++++++++++++++++++ src/datatypes.h | 28 ++++++++ src/driver.h | 61 +++++++++++++++++ src/libvirt.c | 53 +++++++++++++++ src/libvirt_private.syms | 2 + src/virterror.c | 6 ++ 7 files changed, 306 insertions(+), 0 deletions(-)
ACK, with exception of
+typedef unsigned char * + (*virDrvSecretGetValue) (virSecretPtr secret, + size_t *value_size, + bool libvirt_internal_call, + unsigned int flags);
The 'bool libvirt_internal_call' bit is not too nice - the driver.h prototypes should always match the public API prototypes exactly. This is there so that public API callers can't get the value of a secret which has the private='yes' attribute set in its XML. Ultimately this kind of thing needs to be done using a API-wide access control mechanism in the public API, so that we can do more fine grained control. eg, allow a sufficiently authenticated user to see even private secrets, but not everyone else. For now, I think we should just make use of the existing unused flags parameter on this API - we already do that for a few other places. eg, In secret_driver.h define a enum { VIR_SECRET_VALUE_PRIVATE = (1<<16) }; And in the virSecretGetValue() impl in src/libvirt.c, mask out the top 16 bits of the flags passed in from the public API, to prevent them ever setting this flag behind our backs. Thus, internal code can just pass VIR_SECRET_VALUE_PRIVATE directly to the driver methods (which bypass the checking). 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 :|

Changes since the third submission: - Add "flags" parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. --- include/libvirt/virterror.h | 2 + src/libvirt.c | 504 +++++++++++++++++++++++++++++++++++++++++++ src/virterror.c | 9 + 3 files changed, 515 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 bea60f4..c544297 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 * @@ -8679,3 +8704,482 @@ 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. + * @flags: flags, use 0 for now + * + * 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, unsigned int flags) +{ + VIR_DEBUG("conn=%p, xml=%s, flags=%u", conn, xml, flags); + + 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, flags); + 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 + * @flags: flags, use 0 for now + * + * 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, unsigned int flags) +{ + virConnectPtr conn; + + VIR_DEBUG("secret=%p, flags=%u", secret, flags); + + 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, flags); + 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 + * @flags: flags, use 0 for now + * + * 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, unsigned int flags) +{ + virConnectPtr conn; + + VIR_DEBUG("secret=%p, value=%p, value_size=%zu, flags=%u", secret, value, + value_size, flags); + + 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, flags); + 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 + * @flags: flags, use 0 for now + * + * 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, unsigned int flags) +{ + virConnectPtr conn; + + VIR_DEBUG("secret=%p, value_size=%p, flags=%u", secret, value_size, flags); + + 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, flags); + 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 Thu, Aug 20, 2009 at 08:18:01PM +0200, Miloslav Trma?? wrote:
Changes since the third submission: - Add "flags" parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. --- include/libvirt/virterror.h | 2 + src/libvirt.c | 504 +++++++++++++++++++++++++++++++++++++++++++ src/virterror.c | 9 + 3 files changed, 515 insertions(+), 0 deletions(-)
ACK, this is fine 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 :|

Changes since the third submission: - Add "flags" parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. --- 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 | 140 ++++++++++++++++++++++++++++++++++++ qemud/remote_protocol.h | 122 +++++++++++++++++++++++++++++++ qemud/remote_protocol.x | 83 +++++++++++++++++++++- 7 files changed, 453 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..db4d794 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,137 @@ 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; + if (!xdr_u_int (xdrs, &objp->flags)) + 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; + if (!xdr_u_int (xdrs, &objp->flags)) + 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; + if (!xdr_u_int (xdrs, &objp->flags)) + 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; + if (!xdr_u_int (xdrs, &objp->flags)) + 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..b54b3ae 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,85 @@ 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; + u_int flags; +}; +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; + u_int flags; +}; +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; + u_int flags; +}; +typedef struct remote_secret_set_value_args remote_secret_set_value_args; + +struct remote_secret_get_value_args { + remote_nonnull_secret secret; + u_int flags; +}; +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 +1655,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 +1702,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 +1926,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 +1954,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 +2178,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..006dfa1 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,63 @@ 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; + unsigned flags; +}; + +struct remote_secret_define_xml_ret { + remote_nonnull_secret secret; +}; + +struct remote_secret_get_xml_desc_args { + remote_nonnull_secret secret; + unsigned flags; +}; + +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>; + unsigned flags; +}; + +struct remote_secret_get_value_args { + remote_nonnull_secret secret; + unsigned flags; +}; + +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 +1496,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

On Thu, Aug 20, 2009 at 08:18:02PM +0200, Miloslav Trma?? wrote:
Changes since the third submission: - Add "flags" parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. --- 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 | 140 ++++++++++++++++++++++++++++++++++++ qemud/remote_protocol.h | 122 +++++++++++++++++++++++++++++++ qemud/remote_protocol.x | 83 +++++++++++++++++++++- 7 files changed, 453 insertions(+), 1 deletions(-)
ACK, wire protocol looks good 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 :|

Changes since the third submission: - Add "flags" parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. --- src/datatypes.h | 1 + src/remote_internal.c | 328 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 329 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 de3c288..682a904 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,305 @@ 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, unsigned int flags) +{ + 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; + args.flags = flags; + + 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, unsigned int flags) +{ + 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); + args.flags = flags; + + 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, unsigned int flags) +{ + 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; + args.flags = flags; + + 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 int flags) +{ + 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); + args.flags = flags; + + 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 +7716,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 +7761,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 +7920,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 +7971,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 Thu, Aug 20, 2009 at 08:18:03PM +0200, Miloslav Trma?? wrote:
Changes since the third submission: - Add "flags" parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. --- src/datatypes.h | 1 + src/remote_internal.c | 328 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 329 insertions(+), 0 deletions(-)
ACK, client code is fine. 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 :|

Changes since the third submission: - Add "flags" parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. --- qemud/remote.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 203 insertions(+), 0 deletions(-) diff --git a/qemud/remote.c b/qemud/remote.c index d32d513..2258dec 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, args->flags); + 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, args->flags); + 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, args->flags); + 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, args->flags) < 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 Thu, Aug 20, 2009 at 08:18:04PM +0200, Miloslav Trma?? wrote:
Changes since the third submission: - Add "flags" parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. --- qemud/remote.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 203 insertions(+), 0 deletions(-)
ACK all straightforward stuff. 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 :|

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 third submission: - Add "flags" parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. - Add the base64 gnulib module here, not in a later patch - Don't use fprintf(stderr) for logging - Move an assignment out of loop termination test - fchmod() a newly created temporary file before writing secrets to it - Reject invalid XML attribute values - Use more verbose errors in parseKeyValue() - Use open()+fstat() instead of stat()+open() - Fix structure declaration formatting - Fix error message formatting - Remove a comment suggesting use of abort() --- bootstrap | 1 + 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 | 1152 +++++++++++++++++++++++++++++++++++++++++++ src/secret_driver.h | 28 + src/test.c | 21 + src/virterror.c | 5 + 10 files changed, 1228 insertions(+), 0 deletions(-) create mode 100644 src/secret_driver.c create mode 100644 src/secret_driver.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/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 f2c0736..8b22030 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -299,6 +299,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..f8180ad --- /dev/null +++ b/src/secret_driver.c @@ -0,0 +1,1152 @@ +/* + * 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 "logging.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) + +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; /* May be NULL */ + char *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; *pptr != NULL; pptr = &s->next) { + s = *pptr; + 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; + } + if (fchmod(fd, S_IRUSR | S_IWUSR) != 0) { + virReportSystemError (conn, errno, _("fchmod(\"%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 { + virSecretReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("invalid format of 'ephemeral' for secret " + "with id '%s'"), + s->id != NULL ? s->id : "(NULL)"); + return -1; + } + } else if (STREQ(key, "private")) { + if (STREQ(value, "yes")) + s->private = 1; + else if (STREQ(value, "no")) + s->private = 0; + else { + virSecretReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("invalid format of 'private' for secret " + "with id '%s'"), + s->id != NULL ? s->id : "(NULL)"); + return -1; + } + } else if (STREQ(key, "value")) { + char *raw; + + if (s->value != NULL) { + virSecretReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("duplicate 'value' of secret with id '%s'"), + s->id != NULL ? s->id : "(NULL)"); + return -1; + } + if (!base64_decode_alloc(value, strlen(value), &raw, &s->value_size)) { + virSecretReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("invalid format of base64 for value of " + "secret with id '%s'"), + s->id != NULL ? s->id : "(NULL)"); + return -1; + } + if (raw == NULL) + goto no_memory; + s->value = (unsigned char *)raw; + } else if (STREQ(key, "description")) { + if (s->description != NULL) { + virSecretReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("duplicate 'description' of secret with id " + "'%s'"), s->id != NULL ? s->id : "(NULL)"); + return -1; + } + if (parseBase64String(conn, value, &s->description) < 0) + return -1; + } else if (STREQ(key, "volume")) { + if (s->volume != NULL) { + virSecretReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("duplicate 'volume' of secret with id '%s'"), + s->id != NULL ? s->id : "(NULL)"); + return -1; + } + if (parseBase64String(conn, value, &s->volume) < 0) + return -1; + } else { + virSecretReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("invalid keyword in secret storage")); + return -1; + } + + return 0; + + 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; + + fd = open(driver->filename, O_RDONLY); + if (fd == -1) { + if (errno == ENOENT) + return 0; + virReportSystemError (conn, errno, _("cannot open '%s'"), + driver->filename); + goto cleanup; + } + + if (fstat(fd, &st) < 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; + } + + 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 (contents != NULL) { + memset(contents, 0, st.st_size); + VIR_FREE(contents); + } + if (fd != -1) + close(fd); + return ret; +} + +static virSecretEntryPtr +secretXMLParseNode(virConnectPtr conn, xmlDocPtr xml, xmlNodePtr root) +{ + xmlXPathContextPtr ctxt = NULL; + virSecretEntryPtr secret = NULL, ret = NULL; + char *prop = NULL; + + 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) { + if (STREQ(prop, "yes")) + secret->ephemeral = 1; + else if (STREQ(prop, "no")) + secret->ephemeral = 0; + else { + virSecretReportError(conn, VIR_ERR_XML_ERROR, "%s", + _("invalid value of 'ephemeral'")); + goto cleanup; + } + VIR_FREE(prop); + } + + prop = virXPathString(conn, "string(./@private)", ctxt); + if (prop != NULL) { + if (STREQ(prop, "yes")) + secret->private = 1; + else if (STREQ(prop, "no")) + secret->private = 0; + else { + virSecretReportError(conn, VIR_ERR_XML_ERROR, "%s", + _("invalid value of 'private'")); + goto cleanup; + } + 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: + VIR_FREE(prop); + 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, + unsigned int flags ATTRIBUTE_UNUSED) +{ + 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) + 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, unsigned int flags ATTRIBUTE_UNUSED) +{ + 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, unsigned int flags ATTRIBUTE_UNUSED) +{ + 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, unsigned int flags ATTRIBUTE_UNUSED) +{ + 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) { + 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: + VIR_ERROR0(_("Out of memory initializing secrets")); + 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 Thu, Aug 20, 2009 at 08:18:05PM +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.)
Looking at this in more detail now, I think we ought to change the way the simple file store works. WIth this code all the secrets end up in one big file id NzFkMDY4ZjMtMzU0ZS0xYTUxLTI0MWMtNWJmNmQ1ZjY4Zjhk ephemeral no private yes description TFVLUyBwYXNzcGhyYXNlIGZvciBvdXIgbWFpbCBzZXJ2ZXI= volume L2hvbWUvYmVycmFuZ2UvbWFpbC5pbWc= id YTY3Yzk0YWMtN2RiNi1iNjYxLWIwNGMtMDU4YzFlYWMyNTEy ephemeral no private yes description TFVLUyBwYXNzcGhyYXNlIGZvciBvdXIgbWFpbCBzZXJ2ZXI= volume L2hvbWUvYmVycmFuZ2UvbWFpbC5pbWc= id MWI0ZmRlNmYtMDkyOS0zYmI1LWMyYWEtMGY2MmVmNzllNTJh ephemeral no private yes Since this is re-written to disk everytime something is changed, it poses quite a risk of data loss. It also means we've got yet another file format parser/formatter. How about doing something arguably even simpler $LIBVIRT_CONFIG_DIR | +- secrets | +- 7c2c8591-eb89-d373-3bcf-0957b84210fc.xml +- 7c2c8591-eb89-d373-3bcf-0957b84210fc.base64 +- 3174ee25-1be0-ba8f-1c99-d0b929226d7e.xml +- 3174ee25-1be0-ba8f-1c99-d0b929226d7e.base64 ie, a directory 'secrets', and in that directory the 'XXX.xml' file is just the stuff passed in from virSecretDefineXML. The XXX.base64 file contains just the bae64 encoded secret value, or simply does not exist if no secret has been set yet. This means we never have to worry about re-writing existing files. Using the existing XML format for the metadata means we don't need another file format parser. Finally having the secret value separate in a .base64 file means we can read/write it without the secret data being copied around all over the place by the XML parser, and can trivially switch to gpgme later, by just using XXXX.gpg for the secret data - which is nicely upgradable too - since code can simply check for XXX.gpg, and fallback to XXX.base64 if it wasn't found.
+ +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; /* May be NULL */ + char *volume; /* May be NULL */ +};
This struct and the parse/format methods just below here...
+ +static virSecretEntryPtr +secretXMLParseNode(virConnectPtr conn, xmlDocPtr xml, xmlNodePtr root) +{ + xmlXPathContextPtr ctxt = NULL; + virSecretEntryPtr secret = NULL, ret = NULL; + char *prop = NULL; + + 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) { + if (STREQ(prop, "yes")) + secret->ephemeral = 1; + else if (STREQ(prop, "no")) + secret->ephemeral = 0; + else { + virSecretReportError(conn, VIR_ERR_XML_ERROR, "%s", + _("invalid value of 'ephemeral'")); + goto cleanup; + } + VIR_FREE(prop); + } + + prop = virXPathString(conn, "string(./@private)", ctxt); + if (prop != NULL) { + if (STREQ(prop, "yes")) + secret->private = 1; + else if (STREQ(prop, "no")) + secret->private = 0; + else { + virSecretReportError(conn, VIR_ERR_XML_ERROR, "%s", + _("invalid value of 'private'")); + goto cleanup; + } + 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: + VIR_FREE(prop); + 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; +}
should be moved into a separate 'secret_conf.h' and 'secret_conf.c' file, and linked to the base libvirt_driver.la This would let the later patches touching storage_backend.c and qemu_driver.c to use the virSecretEntry struct directly, and then just call the XML formattter/parsers, instead of having to include their own copies of the XML formatting code. Regards, 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 :|

Changes since the third submission: - Add "flags" parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. - Add documentation to virsh.1 --- docs/virsh.pod | 43 ++++++++ src/virsh.c | 323 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ virsh.1 | 34 ++++++- 3 files changed, 399 insertions(+), 1 deletions(-) diff --git a/docs/virsh.pod b/docs/virsh.pod index 10bb991..55ec64a 100644 --- a/docs/virsh.pod +++ b/docs/virsh.pod @@ -543,6 +543,49 @@ Convert a network name to network UUID. =back +=head1 SECRET COMMMANDS + +The following commands manipulate "secrets" (e.g. passwords, passphrases and +encryption keys). Libvirt can store secrets independently from their use, and +other objects (e.g. volumes or domains) can refer to the secrets for encryption +or possibly other uses. Secrets are identified using an UUID. See +L<http://libvirt.org/formatsecret.html> for documentation of the XML format +used to represent properties of secrets. + +=over 4 + +=item B<secret-define> I<file> + +Create a secret with the properties specified in I<file>, with no associated +secret value. If I<file> does not specify a UUID, choose one automatically. +If I<file> specifies an UUID of an existing secret, replace its properties by +properties defined in I<file>, without affecting the secret value. + +=item B<secret-dumpxml> I<secret> + +Output properties of I<secret> (specified by its UUID) as an XML dump to stdout. + +=item B<secret-set-value> I<secret> I<base64> + +Set the value associated with I<secret> (specified by its UUID) to the value +Base64-encoded value I<base64>. + +=item B<secret-get-value> I<secret> + +Output the value associated with I<secret> (specified by its UUID) to stdout, +encoded using Base64. + +=item B<secret-undefine> I<secret> + +Delete a I<secret> (specified by its UUID), including the associated value, if +any. + +=item B<secret-list> + +Output a list of UUIDs of known secrets to stdout. + +=back + =head1 ENVIRONMENT The following environment variables can be set to alter the behaviour diff --git a/src/virsh.c b/src/virsh.c index 2d0cf81..1b073ef 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, 0); + 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, 0); + 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, 0); + 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, 0); + 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; +} /* @@ -6923,6 +7209,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 @@ -7482,6 +7776,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 */ diff --git a/virsh.1 b/virsh.1 index 0a5b1c1..5731b4c 100644 --- a/virsh.1 +++ b/virsh.1 @@ -132,7 +132,7 @@ .\" ======================================================================== .\" .IX Title "VIRSH 1" -.TH VIRSH 1 "2009-08-11" "libvirt-0.7.0" "Virtualization Support" +.TH VIRSH 1 "2009-08-20" "libvirt-0.7.0" "Virtualization Support" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l @@ -593,6 +593,38 @@ Undefine the configuration for an inactive network. .IP "\fBnet-uuid\fR \fInetwork-name\fR" 4 .IX Item "net-uuid network-name" Convert a network name to network \s-1UUID\s0. +.SH "SECRET COMMMANDS" +.IX Header "SECRET COMMMANDS" +The following commands manipulate \*(L"secrets\*(R" (e.g. passwords, passphrases and +encryption keys). Libvirt can store secrets independently from their use, and +other objects (e.g. volumes or domains) can refer to the secrets for encryption +or possibly other uses. Secrets are identified using an \s-1UUID\s0. See +<http://libvirt.org/formatsecret.html> for documentation of the \s-1XML\s0 format +used to represent properties of secrets. +.IP "\fBsecret-define\fR \fIfile\fR" 4 +.IX Item "secret-define file" +Create a secret with the properties specified in \fIfile\fR, with no associated +secret value. If \fIfile\fR does not specify a \s-1UUID\s0, choose one automatically. +If \fIfile\fR specifies an \s-1UUID\s0 of an existing secret, replace its properties by +properties defined in \fIfile\fR, without affecting the secret value. +.IP "\fBsecret-dumpxml\fR \fIsecret\fR" 4 +.IX Item "secret-dumpxml secret" +Output properties of \fIsecret\fR (specified by its \s-1UUID\s0) as an \s-1XML\s0 dump to stdout. +.IP "\fBsecret-set-value\fR \fIsecret\fR \fIbase64\fR" 4 +.IX Item "secret-set-value secret base64" +Set the value associated with \fIsecret\fR (specified by its \s-1UUID\s0) to the value +Base64\-encoded value \fIbase64\fR. +.IP "\fBsecret-get-value\fR \fIsecret\fR" 4 +.IX Item "secret-get-value secret" +Output the value associated with \fIsecret\fR (specified by its \s-1UUID\s0) to stdout, +encoded using Base64. +.IP "\fBsecret-undefine\fR \fIsecret\fR" 4 +.IX Item "secret-undefine secret" +Delete a \fIsecret\fR (specified by its \s-1UUID\s0), including the associated value, if +any. +.IP "\fBsecret-list\fR" 4 +.IX Item "secret-list" +Output a list of UUIDs of known secrets to stdout. .SH "ENVIRONMENT" .IX Header "ENVIRONMENT" The following environment variables can be set to alter the behaviour -- 1.6.2.5

On Thu, Aug 20, 2009 at 08:18:06PM +0200, Miloslav Trma?? wrote:
Changes since the third submission: - Add "flags" parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. - Add documentation to virsh.1 --- docs/virsh.pod | 43 ++++++++ src/virsh.c | 323 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ virsh.1 | 34 ++++++- 3 files changed, 399 insertions(+), 1 deletions(-)
Functionally this patch looks fine, but having tried it out I'm wondering about the 'secret-list' command output...
+/* + * "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; +}
eg, i defined 6 secrets, and now the listing shows. # ./src/virsh secret-list UUID ----------------------------------------- 1b4fde6f-0929-3bb5-c2aa-0f62ef79e52a 3174ee25-1be0-ba8f-1c99-d0b929226d7e 71d068f3-354e-1a51-241c-5bf6d5f68f8d 7c2c8591-eb89-d373-3bcf-0957b84210fc a67c94ac-7db6-b661-b04c-058c1eac2512 de96f05d-ca6a-2fa9-8c65-4e13f2a399d7 which isn't very user friendly. I think we need to try and get info about the usage of the secret included in the output, eg consider if we allowed use of the secrets API for managing per guest secrets for the VNC server too, then I could imagine a display like # ./src/virsh secret-list UUID Usage Object ---------------------------------------------------- 1b4fde6f-0929-3bb5-c2aa-0f62ef79e52a volume /var/lib/libvirt/images/demo.img 3174ee25-1be0-ba8f-1c99-d0b929226d7e volume /var/lib/libvirt/images/mail.img 71d068f3-354e-1a51-241c-5bf6d5f68f8d volume /var/lib/libvirt/images/db.img 7c2c8591-eb89-d373-3bcf-0957b84210fc vnc mailguest a67c94ac-7db6-b661-b04c-058c1eac2512 vnc dbguest de96f05d-ca6a-2fa9-8c65-4e13f2a399d7 vnc demo This might suggest that we have 1 or 2 more public APIs, const char *virSecretGetUsage(virSecretPtr sec); const char *virSecretGetObject(virSecretPtr sec); and, probably that we include those 2 attributes in the virSecretPtr struct defined in src/datatypes.h, so that calling those 2 APis does not incur further RPC calls. This would also mean that we'd have to extend struct remote_nonnull_secret { remote_nonnull_string uuid; }; to include struct remote_nonnull_secret { remote_nonnull_string uuid; remote_nonnull_string usage; remote_nonnull_string object; }; 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 :|

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 | 119 ++++++++++- docs/libvirt-refs.xml | 393 ++++++++++++++++++++++++----------- 6 files changed, 502 insertions(+), 143 deletions(-) diff --git a/docs/devhelp/libvirt-libvirt.html b/docs/devhelp/libvirt-libvirt.html index 0ac96d5..dac0e4f 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, <br/> unsigned int flags); 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, <br/> unsigned int flags); 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, <br/> unsigned int flags); <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, <br/> unsigned int flags); <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/> unsigned int flags)<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>flags</tt></i>:</span></td><td>flags, use 0 for now</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/> unsigned int flags)<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>flags</tt></i>:</span></td><td>flags, use 0 for now</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/> unsigned int flags)<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>flags</tt></i>:</span></td><td>flags, use 0 for now</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/> unsigned int flags)<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>flags</tt></i>:</span></td><td>flags, use 0 for now</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..9bc70e6 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, <br /> unsigned int flags) +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, <br /> unsigned int flags) +char * <a href="#virSecretGetXMLDesc">virSecretGetXMLDesc</a> (<a href="libvirt-libvirt.html#virSecretPtr">virSecretPtr</a> secret, <br /> unsigned int flags) +<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, <br /> unsigned int flags) +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, <! br /> unsigned int flags)<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>flags</tt></i>:</span></td><td>flags, use 0 for now</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 virSecret! Free (<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 /> unsigned int flags)<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>flags</tt></i>:</span></td><td>flags, use 0 for now</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 /> unsigned int flags)<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>flags</tt></i>:</span></td><td>flags, use 0 for now</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 /> unsigned int flags)<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>flags</tt></i>:</span></td><td>flags, use 0 for now</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..1bc5ec1 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,65 @@ 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.'/> + <arg name='flags' type='unsigned int' info='flags, use 0 for now'/> + </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'/> + <arg name='flags' type='unsigned int' info='flags, use 0 for now'/> + </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'/> + <arg name='flags' type='unsigned int' info='flags, use 0 for now'/> + </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'/> + <arg name='flags' type='unsigned int' info='flags, use 0 for now'/> + </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..4dffe14 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'/> @@ -1038,6 +1090,10 @@ <ref name='virNodeDeviceGetXMLDesc'/> <ref name='virNodeListDevices'/> <ref name='virNodeNumOfDevices'/> + <ref name='virSecretDefineXML'/> + <ref name='virSecretGetValue'/> + <ref name='virSecretGetXMLDesc'/> + <ref name='virSecretSetValue'/> <ref name='virStoragePoolBuild'/> <ref name='virStoragePoolCreate'/> <ref name='virStoragePoolCreateXML'/> @@ -1101,6 +1157,7 @@ <ref name='virConnectListDomains'/> <ref name='virConnectListInterfaces'/> <ref name='virConnectListNetworks'/> + <ref name='virConnectListSecrets'/> <ref name='virConnectListStoragePools'/> <ref name='virConnectNumOfDefinedDomains'/> <ref name='virConnectNumOfDefinedInterfaces'/> @@ -1109,6 +1166,7 @@ <ref name='virConnectNumOfDomains'/> <ref name='virConnectNumOfInterfaces'/> <ref name='virConnectNumOfNetworks'/> + <ref name='virConnectNumOfSecrets'/> <ref name='virConnectNumOfStoragePools'/> <ref name='virConnectRef'/> <ref name='virDomainCreateLinux'/> @@ -1136,6 +1194,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 +1342,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 +1547,7 @@ <ref name='virConnectListDomains'/> <ref name='virConnectListInterfaces'/> <ref name='virConnectListNetworks'/> + <ref name='virConnectListSecrets'/> <ref name='virConnectListStoragePools'/> <ref name='virConnectNumOfDefinedDomains'/> <ref name='virConnectNumOfDefinedInterfaces'/> @@ -1485,6 +1556,7 @@ <ref name='virConnectNumOfDomains'/> <ref name='virConnectNumOfInterfaces'/> <ref name='virConnectNumOfNetworks'/> + <ref name='virConnectNumOfSecrets'/> <ref name='virConnectNumOfStoragePools'/> <ref name='virConnectOpen'/> <ref name='virConnectOpenAuth'/> @@ -1631,6 +1703,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 +1792,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 +1809,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 +1853,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 +1870,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 +2054,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 +2133,7 @@ </letter> <letter name='F'> <word name='Fetch'> + <ref name='virConnectNumOfSecrets'/> <ref name='virNodeDeviceGetXMLDesc'/> <ref name='virStoragePoolGetName'/> <ref name='virStoragePoolGetUUID'/> @@ -2062,6 +2154,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 +2177,7 @@ <ref name='virNetworkGetUUIDString'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -2139,6 +2236,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -2156,6 +2254,7 @@ <ref name='virDomainGetConnect'/> <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -2199,6 +2298,7 @@ </word> <word name='List'> <ref name='_virConnectAuth'/> + <ref name='virConnectListSecrets'/> </word> <word name='Lists'> <ref name='virNodeDeviceListCaps'/> @@ -2297,6 +2397,9 @@ <word name='Optional'> <ref name='_virConnectCredential'/> </word> + <word name='Otherwise'> + <ref name='virSecretDefineXML'/> + </word> </letter> <letter name='P'> <word name='PCI'> @@ -2310,6 +2413,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 +2454,7 @@ <ref name='virNetworkGetBridgeName'/> <ref name='virNetworkGetConnect'/> <ref name='virNodeNumOfDevices'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -2378,6 +2488,7 @@ <ref name='virConnectDomainEventRegister'/> </word> <word name='Release'> + <ref name='virSecretFree'/> <ref name='virStorageVolFree'/> </word> <word name='Remaining'> @@ -2431,6 +2542,7 @@ <ref name='virSetErrorFunc'/> </word> <word name='Sets'> + <ref name='virSecretSetValue'/> <ref name='virStoragePoolSetAutostart'/> </word> <word name='Shutdown'> @@ -2444,6 +2556,9 @@ <ref name='virConnGetLastError'/> <ref name='virDomainMigrate'/> </word> + <word name='Size'> + <ref name='virSecretSetValue'/> + </word> <word name='Some'> <ref name='virDomainMigrate'/> </word> @@ -2519,6 +2634,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 +2698,9 @@ <ref name='virNetworkGetUUIDString'/> <ref name='virStoragePoolGetUUIDString'/> </word> + <word name='Value'> + <ref name='virSecretSetValue'/> + </word> </letter> </chunk> <chunk name='chunk2'> @@ -2586,6 +2709,7 @@ <ref name='virDomainGetConnect'/> <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -2596,6 +2720,7 @@ <ref name='virDomainGetConnect'/> <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -2690,6 +2815,7 @@ <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> <ref name='virNodeGetCellsFreeMemory'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -2739,6 +2865,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 +2934,7 @@ </word> <word name='any'> <ref name='virNodeDeviceDettach'/> + <ref name='virSecretDefineXML'/> <ref name='virStoragePoolDestroy'/> </word> <word name='anymore'> @@ -2827,6 +2956,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -2843,34 +2973,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 +3002,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 +3031,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 +3047,7 @@ <ref name='virDomainSetAutostart'/> <ref name='virNetworkGetAutostart'/> <ref name='virNetworkSetAutostart'/> + <ref name='virSecretDefineXML'/> <ref name='virStoragePoolGetAutostart'/> </word> <word name='autostart'> @@ -2995,6 +3104,7 @@ <ref name='virNetworkLookupByName'/> <ref name='virNetworkLookupByUUID'/> <ref name='virNetworkLookupByUUIDString'/> + <ref name='virSecretLookupByUUIDString'/> <ref name='virStoragePoolCreateXML'/> <ref name='virStoragePoolDefineXML'/> <ref name='virStoragePoolLookupByName'/> @@ -3045,6 +3155,7 @@ <ref name='virDomainGetConnect'/> <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -3156,6 +3267,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 +3379,9 @@ <word name='choose'> <ref name='virDomainMigrate'/> </word> + <word name='chosen'> + <ref name='virSecretDefineXML'/> + </word> <word name='clean'> <ref name='virResetError'/> </word> @@ -3385,6 +3503,7 @@ <ref name='virDomainSave'/> </word> <word name='continues'> + <ref name='virSecretFree'/> <ref name='virStorageVolFree'/> </word> <word name='control'> @@ -3414,6 +3533,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -3435,6 +3555,7 @@ <ref name='virNodeDeviceRef'/> <ref name='virNodeListDevices'/> <ref name='virNodeNumOfDevices'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -3442,6 +3563,7 @@ <ref name='virDomainGetConnect'/> <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -3474,6 +3596,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 +3616,7 @@ <word name='currently'> <ref name='virConnectDomainXMLFromNative'/> <ref name='virConnectDomainXMLToNative'/> + <ref name='virConnectNumOfSecrets'/> <ref name='virDomainCoreDump'/> <ref name='virNodeDeviceDettach'/> <ref name='virNodeDeviceReAttach'/> @@ -3554,8 +3680,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 +3723,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 +3804,9 @@ <ref name='virDomainCreateXML'/> <ref name='virStoragePoolCreateXML'/> </word> + <word name='discarded'> + <ref name='virSecretDefineXML'/> + </word> <word name='discover'> <ref name='virConnectFindStoragePoolSources'/> </word> @@ -3701,6 +3834,7 @@ <ref name='virConnectDomainXMLToNative'/> <ref name='virConnectFindStoragePoolSources'/> <ref name='virNodeDeviceGetXMLDesc'/> + <ref name='virSecretGetXMLDesc'/> <ref name='virStoragePoolGetXMLDesc'/> <ref name='virStorageVolGetXMLDesc'/> </word> @@ -3725,6 +3859,7 @@ <ref name='virNetworkDefineXML'/> <ref name='virNetworkDestroy'/> <ref name='virNetworkUndefine'/> + <ref name='virSecretUndefine'/> <ref name='virStoragePoolDestroy'/> </word> <word name='doi'> @@ -3807,6 +3942,7 @@ <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> <ref name='virNodeGetCellsFreeMemory'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -3900,6 +4036,7 @@ <ref name='virConnectDomainEventRegister'/> </word> <word name='exist'> + <ref name='virSecretFree'/> <ref name='virStorageVolFree'/> </word> <word name='existing'> @@ -4031,6 +4168,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -4047,35 +4185,6 @@ <ref name='virStoragePoolGetAutostart'/> <ref name='virStoragePoolSetAutostart'/> </word> - <word name='flags'> - <ref name='_virStoragePoolInfo'/> - <ref name='_virStorageVolInfo'/> - <ref name='virConnectFindStoragePoolSources'/> - <ref name='virConnectOpenAuth'/> - <ref name='virDomainCoreDump'/> - <ref name='virDomainMemoryPeek'/> - <ref name='virDomainMigrate'/> - <ref name='virDomainReboot'/> - <ref name='virInterfaceCreate'/> - <ref name='virInterfaceDefineXML'/> - <ref name='virInterfaceDestroy'/> - <ref name='virInterfaceGetXMLDesc'/> - <ref name='virNetworkGetXMLDesc'/> - <ref name='virNodeDeviceGetXMLDesc'/> - <ref name='virNodeListDevices'/> - <ref name='virNodeNumOfDevices'/> - <ref name='virStoragePoolBuild'/> - <ref name='virStoragePoolCreate'/> - <ref name='virStoragePoolCreateXML'/> - <ref name='virStoragePoolDefineXML'/> - <ref name='virStoragePoolDelete'/> - <ref name='virStoragePoolGetXMLDesc'/> - <ref name='virStoragePoolRefresh'/> - <ref name='virStorageVolCreateXML'/> - <ref name='virStorageVolCreateXMLFrom'/> - <ref name='virStorageVolDelete'/> - <ref name='virStorageVolGetXMLDesc'/> - </word> <word name='following:'> <ref name='virDomainMigrate'/> </word> @@ -4089,35 +4198,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 +4241,7 @@ <ref name='virNodeDeviceDestroy'/> <ref name='virNodeDeviceDettach'/> <ref name='virNodeDeviceReAttach'/> + <ref name='virSecretDefineXML'/> <ref name='virStorageVolDelete'/> <ref name='virStorageVolGetKey'/> </word> @@ -4260,8 +4344,6 @@ <ref name='virNodeDeviceReset'/> </word> </letter> - </chunk> - <chunk name='chunk6'> <letter name='h'> <word name='handle'> <ref name='virConnectDomainEventRegister'/> @@ -4271,6 +4353,7 @@ <ref name='virEventRemoveHandleFunc'/> <ref name='virEventRemoveTimeoutFunc'/> <ref name='virEventTimeoutCallback'/> + <ref name='virSecretFree'/> <ref name='virStorageVolFree'/> </word> <word name='handler'> @@ -4316,6 +4399,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolGetKey'/> <ref name='virStorageVolRef'/> @@ -4329,6 +4413,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -4382,6 +4467,8 @@ <ref name='virDomainMigrate'/> </word> </letter> + </chunk> + <chunk name='chunk6'> <letter name='i'> <word name='iSCSI'> <ref name='virConnectFindStoragePoolSources'/> @@ -4442,6 +4529,7 @@ <ref name='virDomainGetConnect'/> <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -4451,6 +4539,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -4502,6 +4591,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 +4685,7 @@ <ref name='virNetworkLookupByUUIDString'/> <ref name='virNodeDeviceLookupByName'/> <ref name='virNodeDeviceReAttach'/> + <ref name='virSecretDefineXML'/> <ref name='virStoragePoolCreateXML'/> <ref name='virStoragePoolDefineXML'/> <ref name='virStoragePoolLookupByName'/> @@ -4610,8 +4703,6 @@ <ref name='virStoragePoolDelete'/> </word> </letter> - </chunk> - <chunk name='chunk7'> <letter name='j'> <word name='join'> <ref name='virNetworkGetBridgeName'/> @@ -4664,6 +4755,7 @@ <ref name='virDomainGetConnect'/> <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -4754,6 +4846,7 @@ <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> <ref name='virNodeGetFreeMemory'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -4833,6 +4926,9 @@ <ref name='virStoragePoolGetName'/> <ref name='virStorageVolLookupByPath'/> </word> + <word name='locates'> + <ref name='virSecretDefineXML'/> + </word> <word name='location'> <ref name='virStoragePoolGetAutostart'/> </word> @@ -4847,6 +4943,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -4871,6 +4968,8 @@ <ref name='virDomainPinVcpu'/> </word> </letter> + </chunk> + <chunk name='chunk7'> <letter name='m'> <word name='machine'> <ref name='virDomainGetAutostart'/> @@ -4984,6 +5083,7 @@ <ref name='virNodeDeviceDettach'/> <ref name='virNodeDeviceReAttach'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolGetXMLDesc'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> @@ -5071,6 +5171,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -5095,13 +5196,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 +5212,7 @@ <ref name='virConnectListDefinedStoragePools'/> <ref name='virConnectListInterfaces'/> <ref name='virConnectListNetworks'/> + <ref name='virConnectListSecrets'/> <ref name='virConnectListStoragePools'/> <ref name='virNodeDeviceListCaps'/> <ref name='virNodeListDevices'/> @@ -5126,6 +5229,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 +5258,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -5209,6 +5316,10 @@ <ref name='virEventUpdateHandleFunc'/> </word> <word name='now'> + <ref name='virSecretDefineXML'/> + <ref name='virSecretGetValue'/> + <ref name='virSecretGetXMLDesc'/> + <ref name='virSecretSetValue'/> <ref name='virStoragePoolBuild'/> <ref name='virStoragePoolCreate'/> <ref name='virStoragePoolCreateXML'/> @@ -5224,6 +5335,8 @@ <ref name='virInterfaceLookupByMACString'/> </word> </letter> + </chunk> + <chunk name='chunk8'> <letter name='o'> <word name='objects'> <ref name='virDomainSetSchedulerParameters'/> @@ -5262,6 +5375,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -5304,6 +5418,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -5359,6 +5474,7 @@ <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> <ref name='virNodeDeviceReset'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -5515,6 +5631,7 @@ <word name='pointers'> <ref name='virConnectListDefinedDomains'/> <ref name='virConnectListDefinedNetworks'/> + <ref name='virConnectListSecrets'/> <ref name='virDomainMemoryPeek'/> </word> <word name='pools'> @@ -5604,6 +5721,7 @@ <ref name='virConnSetErrorFunc'/> <ref name='virConnectListDefinedDomains'/> <ref name='virConnectListDefinedNetworks'/> + <ref name='virConnectListSecrets'/> <ref name='virErrorFunc'/> <ref name='virEventAddHandleFunc'/> <ref name='virSetErrorFunc'/> @@ -5735,6 +5853,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -5754,6 +5873,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -5789,6 +5909,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 +5951,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -6022,6 +6146,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 +6208,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -6172,6 +6301,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 +6390,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 +6411,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 +6592,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virSetErrorFunc'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> @@ -6478,6 +6618,7 @@ <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> <ref name='virResetLastError'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -6494,6 +6635,7 @@ <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> <ref name='virResetLastError'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -6521,6 +6663,7 @@ <ref name='virDomainGetConnect'/> <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -6571,6 +6714,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -6595,6 +6739,7 @@ <ref name='virDomainMigrate'/> <ref name='virDomainPinVcpu'/> <ref name='virDomainSetVcpus'/> + <ref name='virSecretFree'/> <ref name='virStoragePoolBuild'/> <ref name='virStoragePoolDelete'/> <ref name='virStorageVolFree'/> @@ -6640,6 +6785,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolDefineXML'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> @@ -6701,6 +6847,11 @@ <ref name='virNodeDeviceDettach'/> <ref name='virNodeDeviceReAttach'/> <ref name='virNodeDeviceReset'/> + <ref name='virSecretDefineXML'/> + <ref name='virSecretGetConnect'/> + <ref name='virSecretGetValue'/> + <ref name='virSecretGetXMLDesc'/> + <ref name='virSecretSetValue'/> <ref name='virStoragePoolBuild'/> <ref name='virStoragePoolCreate'/> <ref name='virStoragePoolCreateXML'/> @@ -6717,6 +6868,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -6756,6 +6908,7 @@ <ref name='virNodeDeviceCreateXML'/> <ref name='virNodeDeviceDettach'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolCreateXMLFrom'/> <ref name='virStorageVolRef'/> @@ -6763,6 +6916,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 +6929,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 +6960,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 +6990,7 @@ <ref name='virDomainGetConnect'/> <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -6988,6 +7129,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 +7284,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -7184,6 +7340,7 @@ <ref name='virInterfaceRef'/> <ref name='virNetworkRef'/> <ref name='virNodeDeviceRef'/> + <ref name='virSecretRef'/> <ref name='virStoragePoolRef'/> <ref name='virStorageVolRef'/> </word> @@ -7194,6 +7351,7 @@ <ref name='virDomainGetConnect'/> <ref name='virInterfaceGetConnect'/> <ref name='virNetworkGetConnect'/> + <ref name='virSecretGetConnect'/> <ref name='virStoragePoolGetConnect'/> <ref name='virStorageVolGetConnect'/> </word> @@ -7213,6 +7371,7 @@ </word> <word name='xml'> <ref name='virConnectFindStoragePoolSources'/> + <ref name='virSecretDefineXML'/> </word> <word name='xvda'> <ref name='virDomainBlockStats'/> @@ -7253,10 +7412,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

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.UUIDString() '340c2dfb-811b-eda8-da9e-25ccd7bfd650'
s.XMLDesc() "<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.value() 'abc\x00xx\xffx'
s.undefine() 0
Changes since the third submission: - Add "flags" parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. - remove "get" prefix from method names of virSecret, to be more consistent with other classes. --- python/generator.py | 31 +++++++++++-- python/libvir.c | 100 +++++++++++++++++++++++++++++++++++++++++ python/libvirt-python-api.xml | 18 +++++++ python/libvirt_wrap.h | 9 ++++ python/types.c | 13 +++++ 5 files changed, 167 insertions(+), 4 deletions(-) diff --git a/python/generator.py b/python/generator.py index feff7a3..4dbad1c 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,12 @@ 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:12] == 'virSecretGet': + func = name[12:] + 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 +1041,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 +1049,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..e2c196a 100644 --- a/python/libvir.c +++ b/python/libvir.c @@ -1562,6 +1562,103 @@ 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; + unsigned int flags; + + if (!PyArg_ParseTuple(args, (char *)"Oi:virSecretGetValue", &pyobj_secret, + &flags)) + return NULL; + secret = (virSecretPtr) PyvirSecret_Get(pyobj_secret); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virSecretGetValue(secret, &size, flags); + 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; + unsigned int flags; + + if (!PyArg_ParseTuple(args, (char *)"Oz#i:virSecretSetValue", &pyobj_secret, + &value, &size, &flags)) + return NULL; + secret = (virSecretPtr) PyvirSecret_Get(pyobj_secret); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virSecretSetValue(secret, (const unsigned char *)value, size, + flags); + LIBVIRT_END_ALLOW_THREADS; + + py_retval = libvirt_intWrap(c_retval); + return py_retval; +} /******************************************* * Helper functions to avoid importing modules @@ -2261,6 +2358,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..e5c1fb9 100644 --- a/python/libvirt-python-api.xml +++ b/python/libvirt-python-api.xml @@ -172,5 +172,23 @@ <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'/> + <arg name='flags' type='unsigned int' info='flags (unused; pass 0)'/> + </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'/> + <arg name='flags' type='unsigned int' info='flags (unused; pass 0)'/> + </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 Thu, Aug 20, 2009 at 08:18:08PM +0200, Miloslav Trma?? wrote:
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.UUIDString() '340c2dfb-811b-eda8-da9e-25ccd7bfd650'
s.XMLDesc() "<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.value() 'abc\x00xx\xffx'
s.undefine() 0
Changes since the third submission: - Add "flags" parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. - remove "get" prefix from method names of virSecret, to be more consistent with other classes. --- python/generator.py | 31 +++++++++++-- python/libvir.c | 100 +++++++++++++++++++++++++++++++++++++++++ python/libvirt-python-api.xml | 18 +++++++ python/libvirt_wrap.h | 9 ++++ python/types.c | 13 +++++ 5 files changed, 167 insertions(+), 4 deletions(-)
ACK looks good. 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 :|

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 third submission: - Move base64 gnulib module inclusion to an earlier patch --- 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 ++++++++++ 18 files changed, 664 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/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 8b22030..101fbbb 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -346,6 +346,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

On Thu, Aug 20, 2009 at 08:18:09PM +0200, Miloslav Trma?? wrote:
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 third submission: - Move base64 gnulib module inclusion to an earlier patch --- 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 ++++++++++
ACK to the code - will just like src/storage_encryption.h/c renamed to be src/storage_encryption_conf.h/c, but I can do that when we commit it. 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 :|

Anno domini 2009 Miloslav Trmač scripsit:
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 @@
[...]
+#include "base64.h" [...]
Is there any special need for this include? If so, where does this include file come from? My buildbot refused to compile this code as it did not have any base64.h header file. As removing this include solved the build problem for me, I would suggest the following patch if noone objects. Ciao Max -- If it doesn't work, force it. If it breaks, it needed replacing anyway.

On Tue, Sep 01, 2009 at 08:50:16PM +0200, Maximilian Wilhelm wrote:
Anno domini 2009 Miloslav Trma?? scripsit:
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 @@
[...]
+#include "base64.h" [...]
Is there any special need for this include? If so, where does this include file come from?
My buildbot refused to compile this code as it did not have any base64.h header file. As removing this include solved the build problem for me, I would suggest the following patch if noone objects.
Yep, this is only needed by a later patch I've not yet committed. I meant to remove this but forgot. Will commit your fix shortly In the future it will come from gnulib - so as long as you run the autogen.sh script every time you build, it should be fine. 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 :|

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. --- 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

On Thu, Aug 20, 2009 at 08:18:10PM +0200, Miloslav Trma?? wrote:
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. --- 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(-)
ACK 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 :|

(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

On Thu, Aug 20, 2009 at 08:18:11PM +0200, Miloslav Trma?? wrote:
(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(-) @@ -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; + }
I was going to suggest that we check 'crypt_format' == 1, since that indicates AES, but that seems needlessly strict - our code would almost certainly work for any other encryption algorithms they added. So, ACK to this patch 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 :|

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

On Thu, Aug 20, 2009 at 08:18:12PM +0200, Miloslav Trma?? wrote:
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(-)
ACK 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 :|

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 third submission: - Add "flags" parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. --- 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..5fa0035 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, 0); + 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) < 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

On Thu, Aug 20, 2009 at 08:18:13PM +0200, Miloslav Trma?? wrote:
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 third submission: - Add "flags" parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. --- 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..5fa0035 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);
This is the first place where we should be just calling into an internal secret_conf.h API for formatting XML from a struct, rather than duplicating the XML formatting.
+ /* 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);
I reckon this snippet of code could usefully be put into the util.h file as virFileGenerateRandomkey(), or alternatively perhaps secret_conf.h, as virSecretGenerateRandomKey(unsigned char *buf, size_t buflen); Regards, 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 :|

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. --- 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 1d2cc7c..46acf5e 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); } @@ -661,6 +662,7 @@ virDomainDiskDefParseXML(virConnectPtr conn, char *bus = NULL; char *cachetag = NULL; char *devaddr = NULL; + virStorageEncryptionPtr encryption = NULL; if (VIR_ALLOC(def) < 0) { virReportOOMError(conn); @@ -718,6 +720,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; @@ -836,6 +844,8 @@ virDomainDiskDefParseXML(virConnectPtr conn, driverName = NULL; def->driverType = driverType; driverType = NULL; + def->encryption = encryption; + encryption = NULL; cleanup: VIR_FREE(bus); @@ -847,6 +857,7 @@ cleanup: VIR_FREE(driverName); VIR_FREE(cachetag); VIR_FREE(devaddr); + virStorageEncryptionFree(encryption); return def; @@ -3519,6 +3530,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

On Thu, Aug 20, 2009 at 08:18:14PM +0200, Miloslav Trma?? wrote:
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. --- 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(-)
ACK, this is fine. 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 :|

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 eb22940..e92276e 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -2473,10 +2473,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

On Thu, Aug 20, 2009 at 08:18:15PM +0200, Miloslav Trma?? wrote:
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 eb22940..e92276e 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -2473,10 +2473,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; }
ACK 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 :|

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 e92276e..3ab0fcc 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, @@ -2406,12 +2419,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; @@ -2455,12 +2469,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 */ @@ -2498,6 +2520,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

On Thu, Aug 20, 2009 at 08:18:16PM +0200, Miloslav Trma?? wrote:
Support arbitrary callbacks for "secondary prompts". Reimplement qemudMonitorCommandExtra using such a callback. --- src/qemu_driver.c | 84 +++++++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 72 insertions(+), 12 deletions(-)
The monitor code is getting really "fun" now :-) ACK to this. 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 :|

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. --- 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 3ab0fcc..d013007 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); @@ -1237,7 +1241,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; @@ -1272,13 +1275,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; @@ -2573,6 +2578,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) { @@ -3057,7 +3076,6 @@ cleanup: static int qemudDomainResume(virDomainPtr dom) { struct qemud_driver *driver = dom->conn->privateData; - char *info; virDomainObjPtr vm; int ret = -1; virDomainEventPtr event = NULL; @@ -3078,17 +3096,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; @@ -3822,13 +3841,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); @@ -4342,13 +4361,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); } @@ -7031,14 +7051,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 @@ -7046,16 +7063,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) @@ -7078,7 +7092,6 @@ qemudDomainMigrateFinish2 (virConnectPtr dconn, virDomainObjPtr vm; virDomainPtr dom = NULL; virDomainEventPtr event = NULL; - char *info = NULL; qemuDriverLock(driver); vm = virDomainFindByName(&driver->domains, dname); @@ -7092,18 +7105,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

On Thu, Aug 20, 2009 at 08:18:17PM +0200, Miloslav Trma?? wrote:
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. --- 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 3ab0fcc..d013007 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);
[snip]
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); }
I think we can do something a little nicer than this 'error_reported' boolean. At the start of every API call we do a 'virResetError', so we can guarentee no error is set. Thus, you ought to be able to see if an error has been set by qemudMonitorSendCont() just by doing once it returns if (virGetLastError() == NULL) The only minor bump on the road in that plan, is that I've just noticed a bug in qemudAutostartConfigs() which fails to call the virResetErrror() before runing qemudStartVMDaemon(), but that's easily fixed. 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 :|

Changes since the third submission: - Add "flags" parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. --- 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 d013007..b73d665 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -1296,12 +1296,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)) { @@ -2578,14 +2572,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, 0); + 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

On Thu, Aug 20, 2009 at 08:18:18PM +0200, Miloslav Trma?? wrote:
Changes since the third submission: - Add "flags" parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. --- src/qemu_driver.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 153 insertions(+), 8 deletions(-)
ACK, looks ok 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 :|
participants (3)
-
Daniel P. Berrange
-
Maximilian Wilhelm
-
Miloslav Trmač