[libvirt] [PATCH 0/6 v4] Atomic API to list secrets

v3 - v4: * Just rebase on the top, split the patches from v3's larget set Osier Yang (6): list: Define new API virConnectListAllSecrets list: Implement RPC calls for virConnectListAllSecrets list: Implement listAllSecrets list: Expose virConnectListAllSecrets to Python binding list: Expose virConnectListAllSecrets to Python binding virsh: Remove unused vshNameSorter daemon/remote.c | 54 ++++++++++ include/libvirt/libvirt.h.in | 3 + python/generator.py | 1 + python/libvirt-override-api.xml | 6 + python/libvirt-override-virConnect.py | 12 ++ python/libvirt-override.c | 48 +++++++++ src/driver.h | 5 + src/libvirt.c | 50 +++++++++ src/libvirt_public.syms | 1 + src/remote/remote_driver.c | 64 ++++++++++++ src/remote/remote_protocol.x | 13 ++- src/remote_protocol-structs | 12 ++ src/secret/secret_driver.c | 59 +++++++++++- tools/virsh-secret.c | 182 +++++++++++++++++++++++++++----- tools/virsh.c | 9 -- tools/virsh.h | 1 - 16 files changed, 479 insertions(+), 41 deletions(-) -- 1.7.7.3

This is to list the secret objects. No flags are supported include/libvirt/libvirt.h.in: Declare enum virConnectListAllSecretFlags and virConnectListAllSecrets. python/generator.py: Skip auto-generating src/driver.h: (virDrvConnectListAllSecrets) src/libvirt.c: Implement the public API src/libvirt_public.syms: Export the symbol to public --- include/libvirt/libvirt.h.in | 3 ++ python/generator.py | 1 + src/driver.h | 5 ++++ src/libvirt.c | 50 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 5 files changed, 60 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 86f640d..75257d9 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -3238,6 +3238,9 @@ int virConnectNumOfSecrets (virConnectPtr conn); int virConnectListSecrets (virConnectPtr conn, char **uuids, int maxuuids); +int virConnectListAllSecrets(virConnectPtr conn, + virSecretPtr **secrets, + unsigned int flags); virSecretPtr virSecretLookupByUUID(virConnectPtr conn, const unsigned char *uuid); virSecretPtr virSecretLookupByUUIDString(virConnectPtr conn, diff --git a/python/generator.py b/python/generator.py index d3163e4..955c893 100755 --- a/python/generator.py +++ b/python/generator.py @@ -466,6 +466,7 @@ skip_function = ( 'virConnectListAllInterfaces', # overridden in virConnect.py 'virConnectListAllNodeDevices', # overridden in virConnect.py 'virConnectListAllNWFilters', # overridden in virConnect.py + 'virConnectListAllSecrets', # overridden in virConnect.py 'virStreamRecvAll', # Pure python libvirt-override-virStream.py 'virStreamSendAll', # Pure python libvirt-override-virStream.py diff --git a/src/driver.h b/src/driver.h index 9984a85..3e69dae 100644 --- a/src/driver.h +++ b/src/driver.h @@ -1567,6 +1567,10 @@ typedef int (*virDrvListSecrets) (virConnectPtr conn, char **uuids, int maxuuids); +typedef int + (*virDrvListAllSecrets) (virConnectPtr conn, + virSecretPtr **secrets, + unsigned int flags); typedef struct _virSecretDriver virSecretDriver; typedef virSecretDriver *virSecretDriverPtr; @@ -1588,6 +1592,7 @@ struct _virSecretDriver { virDrvNumOfSecrets numOfSecrets; virDrvListSecrets listSecrets; + virDrvListAllSecrets listAllSecrets; virDrvSecretLookupByUUID lookupByUUID; virDrvSecretLookupByUsage lookupByUsage; virDrvSecretDefineXML defineXML; diff --git a/src/libvirt.c b/src/libvirt.c index 55a2f4e..f6eb6b9 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -14582,6 +14582,56 @@ error: } /** + * virConnectListAllSecrets: + * @conn: Pointer to the hypervisor connection. + * @secrets: Pointer to a variable to store the array containing the secret + * objects or NULL if the list is not required (just returns the + * number of secrets). + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Collect the list of secrets, and allocate an array to store those objects. + * + * Returns the number of secrets found or -1 and sets @secrets to NULL in case + * of error. On success, the array stored into @secrets is guaranteed to + * have an extra allocated element set to NULL but not included in the return count, + * to make iteration easier. The caller is responsible for calling + * virSecretFree() on each array element, then calling free() on @secrets. + */ +int +virConnectListAllSecrets(virConnectPtr conn, + virSecretPtr **secrets, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, secrets=%p, flags=%x", conn, secrets, flags); + + virResetLastError(); + + if (secrets) + *secrets = NULL; + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + if (conn->secretDriver && + conn->secretDriver->listAllSecrets) { + int ret; + ret = conn->secretDriver->listAllSecrets(conn, secrets, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} + +/** * virConnectListSecrets: * @conn: virConnect connection * @uuids: Pointer to an array to store the UUIDs diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index a918bc8..828b315 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -560,6 +560,7 @@ LIBVIRT_0.10.2 { virConnectListAllNetworks; virConnectListAllNodeDevices; virConnectListAllNWFilters; + virConnectListAllSecrets; virConnectListAllStoragePools; virStoragePoolListAllVolumes; } LIBVIRT_0.10.2; -- 1.7.7.3

On 09/05/12 08:28, Osier Yang wrote:
This is to list the secret objects. No flags are supported
include/libvirt/libvirt.h.in: Declare enum virConnectListAllSecretFlags and virConnectListAllSecrets. python/generator.py: Skip auto-generating src/driver.h: (virDrvConnectListAllSecrets) src/libvirt.c: Implement the public API src/libvirt_public.syms: Export the symbol to public --- include/libvirt/libvirt.h.in | 3 ++ python/generator.py | 1 + src/driver.h | 5 ++++ src/libvirt.c | 50 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 5 files changed, 60 insertions(+), 0 deletions(-)
Looks fine. Peter

On 09/05/2012 12:28 AM, Osier Yang wrote:
This is to list the secret objects. No flags are supported
Any reason we aren't allowing a filter on ephemeral=yes/no and private=yes/no from the secret XML? That is, I think you can usefully introduce two sets of filters based on those two binary properties of a secret. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 2012年09月05日 22:57, Eric Blake wrote:
On 09/05/2012 12:28 AM, Osier Yang wrote:
This is to list the secret objects. No flags are supported
Any reason we aren't allowing a filter on ephemeral=yes/no and private=yes/no from the secret XML?
Just because of I didn't notice those two properties. :-) That is, I think you can usefully
introduce two sets of filters based on those two binary properties of a secret.
Will post a v5, per secret API is on the top of the whole series, there is time space before the other APIs are reviewed. Regards, Osier

The RPC generator doesn't support returning list of object yet, this patch do the work manually. * daemon/remote.c: Implemente the server side handler remoteDispatchConnectListAllSecrets. * src/remote/remote_driver.c: Add remote driver handler remoteConnectListAllSecrets. * src/remote/remote_protocol.x: New RPC procedure REMOTE_PROC_CONNECT_LIST_ALL_SECRETS and structs to represent the args and ret for it. * src/remote_protocol-structs: Likewise. --- daemon/remote.c | 54 +++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 64 ++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 13 ++++++++- src/remote_protocol-structs | 12 ++++++++ 4 files changed, 142 insertions(+), 1 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 00ce9c8..6e2bd8d 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -4427,6 +4427,60 @@ cleanup: return rv; } +static int +remoteDispatchConnectListAllSecrets(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_connect_list_all_secrets_args *args, + remote_connect_list_all_secrets_ret *ret) +{ + virSecretPtr *secrets = NULL; + int nsecrets = 0; + int i; + int rv = -1; + struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); + + if (!priv->conn) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + if ((nsecrets = virConnectListAllSecrets(priv->conn, + args->need_results ? &secrets : NULL, + args->flags)) < 0) + goto cleanup; + + if (secrets && nsecrets) { + if (VIR_ALLOC_N(ret->secrets.secrets_val, nsecrets) < 0) { + virReportOOMError(); + goto cleanup; + } + + ret->secrets.secrets_len = nsecrets; + + for (i = 0; i < nsecrets; i++) + make_nonnull_secret(ret->secrets.secrets_val + i, secrets[i]); + } else { + ret->secrets.secrets_len = 0; + ret->secrets.secrets_val = NULL; + } + + ret->ret = nsecrets; + + rv = 0; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + if (secrets) { + for (i = 0; i < nsecrets; i++) + virSecretFree(secrets[i]); + VIR_FREE(secrets); + } + return rv; +} + /*----- Helpers. -----*/ /* get_nonnull_domain and get_nonnull_network turn an on-wire diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 2afe5b0..0a92339 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -2970,6 +2970,69 @@ done: return rv; } +static int +remoteConnectListAllSecrets(virConnectPtr conn, + virSecretPtr **secrets, + unsigned int flags) +{ + int rv = -1; + int i; + virSecretPtr *tmp_secrets = NULL; + remote_connect_list_all_secrets_args args; + remote_connect_list_all_secrets_ret ret; + + struct private_data *priv = conn->privateData; + + remoteDriverLock(priv); + + args.need_results = !!secrets; + args.flags = flags; + + memset(&ret, 0, sizeof(ret)); + if (call(conn, + priv, + 0, + REMOTE_PROC_CONNECT_LIST_ALL_SECRETS, + (xdrproc_t) xdr_remote_connect_list_all_secrets_args, + (char *) &args, + (xdrproc_t) xdr_remote_connect_list_all_secrets_ret, + (char *) &ret) == -1) + goto done; + + if (secrets) { + if (VIR_ALLOC_N(tmp_secrets, ret.secrets.secrets_len + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + for (i = 0; i < ret.secrets.secrets_len; i++) { + tmp_secrets[i] = get_nonnull_secret (conn, ret.secrets.secrets_val[i]); + if (!tmp_secrets[i]) { + virReportOOMError(); + goto cleanup; + } + } + *secrets = tmp_secrets; + tmp_secrets = NULL; + } + + rv = ret.ret; + +cleanup: + if (tmp_secrets) { + for (i = 0; i < ret.secrets.secrets_len; i++) + if (tmp_secrets[i]) + virSecretFree(tmp_secrets[i]); + VIR_FREE(tmp_secrets); + } + + xdr_free((xdrproc_t) xdr_remote_connect_list_all_secrets_ret, (char *) &ret); + +done: + remoteDriverUnlock(priv); + return rv; +} + /*----------------------------------------------------------------------*/ static virDrvOpenStatus ATTRIBUTE_NONNULL (1) @@ -6038,6 +6101,7 @@ static virSecretDriver secret_driver = { .close = remoteSecretClose, /* 0.7.1 */ .numOfSecrets = remoteNumOfSecrets, /* 0.7.1 */ .listSecrets = remoteListSecrets, /* 0.7.1 */ + .listAllSecrets = remoteConnectListAllSecrets, /* 0.10.2 */ .lookupByUUID = remoteSecretLookupByUUID, /* 0.7.1 */ .lookupByUsage = remoteSecretLookupByUsage, /* 0.7.1 */ .defineXML = remoteSecretDefineXML, /* 0.7.1 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 46269c8..1fc7f25 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -2619,6 +2619,16 @@ struct remote_connect_list_all_nwfilters_ret { unsigned int ret; }; +struct remote_connect_list_all_secrets_args { + int need_results; + unsigned int flags; +}; + +struct remote_connect_list_all_secrets_ret { + remote_nonnull_secret secrets<>; + unsigned int ret; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -2955,7 +2965,8 @@ enum remote_procedure { REMOTE_PROC_CONNECT_LIST_ALL_NETWORKS = 283, /* skipgen skipgen priority:high */ REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES = 284, /* skipgen skipgen priority:high */ REMOTE_PROC_CONNECT_LIST_ALL_NODE_DEVICES = 285, /* skipgen skipgen priority:high */ - REMOTE_PROC_CONNECT_LIST_ALL_NWFILTERS = 286 /* skipgen skipgen priority:high */ + REMOTE_PROC_CONNECT_LIST_ALL_NWFILTERS = 286, /* skipgen skipgen priority:high */ + REMOTE_PROC_CONNECT_LIST_ALL_SECRETS = 287 /* skipgen skipgen priority:high */ /* * Notice how the entries are grouped in sets of 10 ? diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 0dde9fc..afd3608 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2078,6 +2078,17 @@ struct remote_connect_list_all_nwfilters_ret { } filters; u_int ret; }; +struct remote_list_all_secrets_args { + int need_results; + u_int flags; +}; +struct remote_list_all_secrets_ret { + struct { + u_int secrets_len; + remote_nonnull_network * secrets_val; + } secrets; + u_int ret; +}; enum remote_procedure { REMOTE_PROC_OPEN = 1, REMOTE_PROC_CLOSE = 2, @@ -2365,4 +2376,5 @@ enum remote_procedure { REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES = 284, REMOTE_PROC_CONNECT_LIST_ALL_NODE_DEVICES = 285, REMOTE_PROC_CONNECT_LIST_ALL_NWFILTERS = 286, + REMOTE_PROC_CONNECT_LIST_ALL_SECRETS = 287, }; -- 1.7.7.3

On 09/05/12 08:28, Osier Yang wrote:
The RPC generator doesn't support returning list of object yet, this patch do the work manually.
* daemon/remote.c: Implemente the server side handler remoteDispatchConnectListAllSecrets.
* src/remote/remote_driver.c: Add remote driver handler remoteConnectListAllSecrets.
* src/remote/remote_protocol.x: New RPC procedure REMOTE_PROC_CONNECT_LIST_ALL_SECRETS and structs to represent the args and ret for it.
* src/remote_protocol-structs: Likewise. --- daemon/remote.c | 54 +++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 64 ++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 13 ++++++++- src/remote_protocol-structs | 12 ++++++++ 4 files changed, 142 insertions(+), 1 deletions(-)
...
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 0dde9fc..afd3608 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2078,6 +2078,17 @@ struct remote_connect_list_all_nwfilters_ret { } filters; u_int ret; }; +struct remote_list_all_secrets_args { + int need_results; + u_int flags; +}; +struct remote_list_all_secrets_ret { + struct { + u_int secrets_len; + remote_nonnull_network * secrets_val;
This should be remote_nonnull_secret.
+ } secrets; + u_int ret; +}; enum remote_procedure { REMOTE_PROC_OPEN = 1, REMOTE_PROC_CLOSE = 2, @@ -2365,4 +2376,5 @@ enum remote_procedure { REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES = 284, REMOTE_PROC_CONNECT_LIST_ALL_NODE_DEVICES = 285, REMOTE_PROC_CONNECT_LIST_ALL_NWFILTERS = 286, + REMOTE_PROC_CONNECT_LIST_ALL_SECRETS = 287, };
Otherwise looks good. Peter

Simply returns the object list. No filtering. src/secret/secret_driver.c: Implement listAllSecrets --- src/secret/secret_driver.c | 59 +++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 58 insertions(+), 1 deletions(-) diff --git a/src/secret/secret_driver.c b/src/secret/secret_driver.c index 7f92776..ed759ed 100644 --- a/src/secret/secret_driver.c +++ b/src/secret/secret_driver.c @@ -601,7 +601,6 @@ cleanup: return -1; } - static const char * secretUsageIDForDef(virSecretDefPtr def) { @@ -620,6 +619,63 @@ secretUsageIDForDef(virSecretDefPtr def) } } +static int +secretListAllSecrets(virConnectPtr conn, + virSecretPtr **secrets, + unsigned int flags) { + virSecretDriverStatePtr driver = conn->secretPrivateData; + virSecretPtr *tmp_secrets = NULL; + int nsecrets = 0; + int ret_nsecrets = 0; + virSecretPtr secret = NULL; + virSecretEntryPtr entry = NULL; + int i = 0; + int ret = -1; + + virCheckFlags(0, -1); + + secretDriverLock(driver); + + for (entry = driver->secrets; entry != NULL; entry = entry->next) + nsecrets++; + + if (!secrets) { + ret = nsecrets; + goto cleanup; + } + + if (VIR_ALLOC_N(tmp_secrets, nsecrets + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + for (entry = driver->secrets; entry != NULL; entry = entry->next) { + if (!(secret = virGetSecret(conn, + entry->def->uuid, + entry->def->usage_type, + secretUsageIDForDef(entry->def)))) + goto cleanup; + tmp_secrets[ret_nsecrets++] = secret; + } + + *secrets = tmp_secrets; + tmp_secrets = NULL; + ret = ret_nsecrets; + + cleanup: + secretDriverUnlock(driver); + if (tmp_secrets) { + for (i = 0; i < ret_nsecrets; i ++) { + if (tmp_secrets[i]) + virSecretFree(tmp_secrets[i]); + } + } + VIR_FREE(tmp_secrets); + + return ret; +} + + static virSecretPtr secretLookupByUUID(virConnectPtr conn, const unsigned char *uuid) { @@ -1072,6 +1128,7 @@ static virSecretDriver secretDriver = { .close = secretClose, /* 0.7.1 */ .numOfSecrets = secretNumOfSecrets, /* 0.7.1 */ .listSecrets = secretListSecrets, /* 0.7.1 */ + .listAllSecrets = secretListAllSecrets, /* 0.10.2 */ .lookupByUUID = secretLookupByUUID, /* 0.7.1 */ .lookupByUsage = secretLookupByUsage, /* 0.7.1 */ .defineXML = secretDefineXML, /* 0.7.1 */ -- 1.7.7.3

On 09/05/12 08:28, Osier Yang wrote:
Simply returns the object list. No filtering.
src/secret/secret_driver.c: Implement listAllSecrets --- src/secret/secret_driver.c | 59 +++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 58 insertions(+), 1 deletions(-)
diff --git a/src/secret/secret_driver.c b/src/secret/secret_driver.c index 7f92776..ed759ed 100644 --- a/src/secret/secret_driver.c +++ b/src/secret/secret_driver.c @@ -601,7 +601,6 @@ cleanup: return -1; }
-
Please don't include this hunk here. Two empty lines between functions are pretty common (this patch adds that too at the end of secretListAllSecrets().
static const char * secretUsageIDForDef(virSecretDefPtr def) { @@ -620,6 +619,63 @@ secretUsageIDForDef(virSecretDefPtr def) } }
+static int +secretListAllSecrets(virConnectPtr conn, + virSecretPtr **secrets, + unsigned int flags) { + virSecretDriverStatePtr driver = conn->secretPrivateData; + virSecretPtr *tmp_secrets = NULL; + int nsecrets = 0; + int ret_nsecrets = 0; + virSecretPtr secret = NULL; + virSecretEntryPtr entry = NULL; + int i = 0; + int ret = -1; + + virCheckFlags(0, -1); + + secretDriverLock(driver); + + for (entry = driver->secrets; entry != NULL; entry = entry->next) + nsecrets++; + + if (!secrets) { + ret = nsecrets; + goto cleanup; + } + + if (VIR_ALLOC_N(tmp_secrets, nsecrets + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + for (entry = driver->secrets; entry != NULL; entry = entry->next) { + if (!(secret = virGetSecret(conn, + entry->def->uuid, + entry->def->usage_type, + secretUsageIDForDef(entry->def)))) + goto cleanup; + tmp_secrets[ret_nsecrets++] = secret; + } + + *secrets = tmp_secrets; + tmp_secrets = NULL; + ret = ret_nsecrets; + + cleanup: + secretDriverUnlock(driver); + if (tmp_secrets) { + for (i = 0; i < ret_nsecrets; i ++) { + if (tmp_secrets[i]) + virSecretFree(tmp_secrets[i]); + } + } + VIR_FREE(tmp_secrets); + + return ret; +} + + static virSecretPtr secretLookupByUUID(virConnectPtr conn, const unsigned char *uuid) {
Otherwise looks OK. Peter

The implementation is done manually as the generator does not support wrapping lists of C pointers into Python objects. python/libvirt-override-api.xml: Document python/libvirt-override-virConnect.py: Implementation for listAllSecrets. python/libvirt-override.c: Implementation for the wrapper. --- python/libvirt-override-api.xml | 6 ++++ python/libvirt-override-virConnect.py | 12 ++++++++ python/libvirt-override.c | 48 +++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 0 deletions(-) diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index b8ab823..4f609ee 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -368,6 +368,12 @@ <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='virConnectListAllSecrets' file='python'> + <info>returns list of all interfaces</info> + <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> + <arg name='flags' type='unsigned int' info='optional flags'/> + <return type='secret *' info='the list of secrets 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.'/> diff --git a/python/libvirt-override-virConnect.py b/python/libvirt-override-virConnect.py index caca982..6bec66d 100644 --- a/python/libvirt-override-virConnect.py +++ b/python/libvirt-override-virConnect.py @@ -266,3 +266,15 @@ retlist.append(virNWFilter(self, _obj=filter_ptr)) return retlist + + def listAllSecrets(self, flags): + """Returns a list of secret objects""" + ret = libvirtmod.virConnectListAllSecrets(self._o, flags) + if ret is None: + raise libvirtError("virConnectListAllSecrets() failed", conn=self) + + retlist = list() + for secret_ptr in ret: + retlist.append(virSecret(self, _obj=secret_ptr)) + + return retlist diff --git a/python/libvirt-override.c b/python/libvirt-override.c index b344ff5..1fab8ec 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -3592,6 +3592,53 @@ libvirt_virConnectListSecrets(PyObject *self ATTRIBUTE_UNUSED, } static PyObject * +libvirt_virConnectListAllSecrets(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + PyObject *pyobj_conn; + PyObject *py_retval = NULL; + PyObject *tmp = NULL; + virConnectPtr conn; + virSecretPtr *secrets = NULL; + int c_retval = 0; + int i; + unsigned int flags; + + if (!PyArg_ParseTuple(args, (char *)"Oi:virConnectListAllSecrets", + &pyobj_conn, &flags)) + return NULL; + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virConnectListAllSecrets(conn, &secrets, flags); + LIBVIRT_END_ALLOW_THREADS; + if (c_retval < 0) + return VIR_PY_NONE; + + if (!(py_retval = PyList_New(c_retval))) + goto cleanup; + + for (i = 0; i < c_retval; i++) { + if (!(tmp = libvirt_virSecretPtrWrap(secrets[i])) || + PyList_SetItem(py_retval, i, tmp) < 0) { + Py_XDECREF(tmp); + Py_DECREF(py_retval); + py_retval = NULL; + goto cleanup; + } + /* python steals the pointer */ + secrets[i] = NULL; + } + +cleanup: + for (i = 0; i < c_retval; i++) + if (secrets[i]) + virSecretFree(secrets[i]); + VIR_FREE(secrets); + return py_retval; +} + +static PyObject * libvirt_virSecretGetValue(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { PyObject *py_retval; @@ -6183,6 +6230,7 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virSecretGetUUIDString", libvirt_virSecretGetUUIDString, METH_VARARGS, NULL}, {(char *) "virSecretLookupByUUID", libvirt_virSecretLookupByUUID, METH_VARARGS, NULL}, {(char *) "virConnectListSecrets", libvirt_virConnectListSecrets, METH_VARARGS, NULL}, + {(char *) "virConnectListAllSecrets", libvirt_virConnectListAllSecrets, METH_VARARGS, NULL}, {(char *) "virSecretGetValue", libvirt_virSecretGetValue, METH_VARARGS, NULL}, {(char *) "virSecretSetValue", libvirt_virSecretSetValue, METH_VARARGS, NULL}, {(char *) "virNWFilterGetUUID", libvirt_virNWFilterGetUUID, METH_VARARGS, NULL}, -- 1.7.7.3

On 09/05/12 08:28, Osier Yang wrote:
The implementation is done manually as the generator does not support wrapping lists of C pointers into Python objects.
python/libvirt-override-api.xml: Document
python/libvirt-override-virConnect.py: Implementation for listAllSecrets.
python/libvirt-override.c: Implementation for the wrapper. --- python/libvirt-override-api.xml | 6 ++++ python/libvirt-override-virConnect.py | 12 ++++++++ python/libvirt-override.c | 48 +++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 0 deletions(-)
Looks good! Peter

The implementation is done manually as the generator does not support wrapping lists of C pointers into Python objects. python/libvirt-override-api.xml: Document python/libvirt-override-virConnect.py: Implementation for listAllSecrets. python/libvirt-override.c: Implementation for the wrapper. --- tools/virsh-secret.c | 182 ++++++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 153 insertions(+), 29 deletions(-) diff --git a/tools/virsh-secret.c b/tools/virsh-secret.c index abcfdfe..c6193cc 100644 --- a/tools/virsh-secret.c +++ b/tools/virsh-secret.c @@ -290,6 +290,139 @@ cleanup: return ret; } +static int +vshSecretSorter(const void *a, const void *b) +{ + virSecretPtr *sa = (virSecretPtr *) a; + virSecretPtr *sb = (virSecretPtr *) b; + char uuid_sa[VIR_UUID_STRING_BUFLEN]; + char uuid_sb[VIR_UUID_STRING_BUFLEN]; + + if (*sa && !*sb) + return -1; + + if (!*sa) + return *sb != NULL; + + virSecretGetUUIDString(*sa, uuid_sa); + virSecretGetUUIDString(*sb, uuid_sb); + + return vshStrcasecmp(uuid_sa, uuid_sb); +} + +struct vshSecretList { + virSecretPtr *secrets; + size_t nsecrets; +}; +typedef struct vshSecretList *vshSecretListPtr; + +static void +vshSecretListFree(vshSecretListPtr list) +{ + int i; + + if (list && list->nsecrets) { + for (i = 0; i < list->nsecrets; i++) { + if (list->secrets[i]) + virSecretFree(list->secrets[i]); + } + VIR_FREE(list->secrets); + } + VIR_FREE(list); +} + +static vshSecretListPtr +vshSecretListCollect(vshControl *ctl, + unsigned int flags) +{ + vshSecretListPtr list = vshMalloc(ctl, sizeof(*list)); + int i; + int ret; + virSecretPtr secret; + bool success = false; + size_t deleted = 0; + int nsecrets = 0; + char **uuids = NULL; + + /* try the list with flags support (0.10.2 and later) */ + if ((ret = virConnectListAllSecrets(ctl->conn, + &list->secrets, + flags)) >= 0) { + list->nsecrets = ret; + goto finished; + } + + /* check if the command is actually supported */ + if (last_error && last_error->code == VIR_ERR_NO_SUPPORT) { + virFreeError(last_error); + last_error = NULL; + goto fallback; + } + + /* there was an error during the call */ + vshError(ctl, "%s", _("Failed to list node secrets")); + goto cleanup; + + +fallback: + /* fall back to old method (0.9.13 and older) */ + virResetLastError(); + + nsecrets = virConnectNumOfSecrets(ctl->conn); + if (nsecrets < 0) { + vshError(ctl, "%s", _("Failed to count secrets")); + goto cleanup; + } + + if (nsecrets == 0) + return list; + + uuids = vshMalloc(ctl, sizeof(char *) * nsecrets); + + nsecrets = virConnectListSecrets(ctl->conn, uuids, nsecrets); + if (nsecrets < 0) { + vshError(ctl, "%s", _("Failed to list secrets")); + goto cleanup; + } + + list->secrets = vshMalloc(ctl, sizeof(virSecretPtr) * (nsecrets)); + list->nsecrets = 0; + + /* get the secrets */ + for (i = 0; i < nsecrets ; i++) { + if (!(secret = virSecretLookupByUUIDString(ctl->conn, uuids[i]))) + continue; + list->secrets[list->nsecrets++] = secret; + } + + /* truncate secrets that weren't found */ + deleted = nsecrets - list->nsecrets; + +finished: + /* sort the list */ + if (list->secrets && list->nsecrets) + qsort(list->secrets, list->nsecrets, + sizeof(*list->secrets), vshSecretSorter); + + /* truncate the list for not found secret objects */ + if (deleted) + VIR_SHRINK_N(list->secrets, list->nsecrets, deleted); + + success = true; + +cleanup: + for (i = 0; i < nsecrets; i++) + VIR_FREE(uuids[i]); + VIR_FREE(uuids); + + if (!success) { + vshSecretListFree(list); + list = NULL; + } + + return list; +} + /* * "secret-list" command */ @@ -302,56 +435,47 @@ static const vshCmdInfo info_secret_list[] = { static bool cmdSecretList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) { - int maxuuids = 0, i; - char **uuids = NULL; - - maxuuids = virConnectNumOfSecrets(ctl->conn); - if (maxuuids < 0) { - vshError(ctl, "%s", _("Failed to list secrets")); - return false; - } - uuids = vshMalloc(ctl, sizeof(*uuids) * maxuuids); + int i; + vshSecretListPtr list = NULL; + bool ret = false; - maxuuids = virConnectListSecrets(ctl->conn, uuids, maxuuids); - if (maxuuids < 0) { - vshError(ctl, "%s", _("Failed to list secrets")); - VIR_FREE(uuids); + if (!(list = vshSecretListCollect(ctl, 0))) return false; - } - - qsort(uuids, maxuuids, sizeof(char *), vshNameSorter); vshPrintExtra(ctl, "%-36s %s\n", _("UUID"), _("Usage")); vshPrintExtra(ctl, "-----------------------------------------------------------\n"); - for (i = 0; i < maxuuids; i++) { - virSecretPtr sec = virSecretLookupByUUIDString(ctl->conn, uuids[i]); + for (i = 0; i < list->nsecrets; i++) { + virSecretPtr sec = list->secrets[i]; const char *usageType = NULL; - if (!sec) { - VIR_FREE(uuids[i]); - continue; - } - switch (virSecretGetUsageType(sec)) { case VIR_SECRET_USAGE_TYPE_VOLUME: usageType = _("Volume"); break; } + char uuid[VIR_UUID_STRING_BUFLEN]; + if (virSecretGetUUIDString(list->secrets[i], uuid) < 0) { + vshError(ctl, "%s", _("Failed to get uuid of secret")); + goto cleanup; + } + if (usageType) { vshPrint(ctl, "%-36s %s %s\n", - uuids[i], usageType, + uuid, usageType, virSecretGetUsageID(sec)); } else { vshPrint(ctl, "%-36s %s\n", - uuids[i], _("Unused")); + uuid, _("Unused")); } - virSecretFree(sec); - VIR_FREE(uuids[i]); } - VIR_FREE(uuids); - return true; + + ret = true; + +cleanup: + vshSecretListFree(list); + return ret; } const vshCmdDef secretCmds[] = { -- 1.7.7.3

On 09/05/12 08:28, Osier Yang wrote:
The implementation is done manually as the generator does not support wrapping lists of C pointers into Python objects.
python/libvirt-override-api.xml: Document
python/libvirt-override-virConnect.py: Implementation for listAllSecrets.
python/libvirt-override.c: Implementation for the wrapper. ---
Huh, this commit message belongs to the previous patch. This is dealing with virsh.
tools/virsh-secret.c | 182 ++++++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 153 insertions(+), 29 deletions(-)
diff --git a/tools/virsh-secret.c b/tools/virsh-secret.c index abcfdfe..c6193cc 100644 --- a/tools/virsh-secret.c +++ b/tools/virsh-secret.c @@ -290,6 +290,139 @@ cleanup: return ret; }
+static int +vshSecretSorter(const void *a, const void *b) +{ + virSecretPtr *sa = (virSecretPtr *) a; + virSecretPtr *sb = (virSecretPtr *) b; + char uuid_sa[VIR_UUID_STRING_BUFLEN]; + char uuid_sb[VIR_UUID_STRING_BUFLEN]; + + if (*sa && !*sb) + return -1; + + if (!*sa) + return *sb != NULL; + + virSecretGetUUIDString(*sa, uuid_sa); + virSecretGetUUIDString(*sb, uuid_sb); + + return vshStrcasecmp(uuid_sa, uuid_sb); +} + +struct vshSecretList { + virSecretPtr *secrets; + size_t nsecrets; +}; +typedef struct vshSecretList *vshSecretListPtr; + +static void +vshSecretListFree(vshSecretListPtr list) +{ + int i; + + if (list && list->nsecrets) { + for (i = 0; i < list->nsecrets; i++) { + if (list->secrets[i]) + virSecretFree(list->secrets[i]); + } + VIR_FREE(list->secrets); + } + VIR_FREE(list); +} + +static vshSecretListPtr +vshSecretListCollect(vshControl *ctl, + unsigned int flags) +{ + vshSecretListPtr list = vshMalloc(ctl, sizeof(*list)); + int i; + int ret; + virSecretPtr secret; + bool success = false; + size_t deleted = 0; + int nsecrets = 0; + char **uuids = NULL; + + /* try the list with flags support (0.10.2 and later) */ + if ((ret = virConnectListAllSecrets(ctl->conn, + &list->secrets, + flags)) >= 0) { + list->nsecrets = ret; + goto finished; + } + + /* check if the command is actually supported */ + if (last_error && last_error->code == VIR_ERR_NO_SUPPORT) { + virFreeError(last_error); + last_error = NULL;
I added a helper to reset libvirt errors: vshResetLibvirtError();
+ goto fallback; + } + + /* there was an error during the call */ + vshError(ctl, "%s", _("Failed to list node secrets")); + goto cleanup; + + +fallback: + /* fall back to old method (0.9.13 and older) */ + virResetLastError();
This needs to be changed to vshResetLibvirtError() as otherwise we would report a bad error in some cases.
+ + nsecrets = virConnectNumOfSecrets(ctl->conn); + if (nsecrets < 0) { + vshError(ctl, "%s", _("Failed to count secrets")); + goto cleanup; + } + + if (nsecrets == 0) + return list; + + uuids = vshMalloc(ctl, sizeof(char *) * nsecrets); + + nsecrets = virConnectListSecrets(ctl->conn, uuids, nsecrets); + if (nsecrets < 0) { + vshError(ctl, "%s", _("Failed to list secrets")); + goto cleanup; + } + + list->secrets = vshMalloc(ctl, sizeof(virSecretPtr) * (nsecrets)); + list->nsecrets = 0; + + /* get the secrets */ + for (i = 0; i < nsecrets ; i++) { + if (!(secret = virSecretLookupByUUIDString(ctl->conn, uuids[i]))) + continue; + list->secrets[list->nsecrets++] = secret; + } + + /* truncate secrets that weren't found */ + deleted = nsecrets - list->nsecrets; + +finished: + /* sort the list */ + if (list->secrets && list->nsecrets) + qsort(list->secrets, list->nsecrets, + sizeof(*list->secrets), vshSecretSorter); + + /* truncate the list for not found secret objects */ + if (deleted) + VIR_SHRINK_N(list->secrets, list->nsecrets, deleted); + + success = true; + +cleanup: + for (i = 0; i < nsecrets; i++) + VIR_FREE(uuids[i]); + VIR_FREE(uuids); + + if (!success) { + vshSecretListFree(list); + list = NULL; + } + + return list; +} + /* * "secret-list" command */ @@ -302,56 +435,47 @@ static const vshCmdInfo info_secret_list[] = { static bool cmdSecretList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) { - int maxuuids = 0, i; - char **uuids = NULL; - - maxuuids = virConnectNumOfSecrets(ctl->conn); - if (maxuuids < 0) { - vshError(ctl, "%s", _("Failed to list secrets")); - return false; - } - uuids = vshMalloc(ctl, sizeof(*uuids) * maxuuids); + int i; + vshSecretListPtr list = NULL; + bool ret = false;
- maxuuids = virConnectListSecrets(ctl->conn, uuids, maxuuids); - if (maxuuids < 0) { - vshError(ctl, "%s", _("Failed to list secrets")); - VIR_FREE(uuids); + if (!(list = vshSecretListCollect(ctl, 0))) return false; - } - - qsort(uuids, maxuuids, sizeof(char *), vshNameSorter);
vshPrintExtra(ctl, "%-36s %s\n", _("UUID"), _("Usage")); vshPrintExtra(ctl, "-----------------------------------------------------------\n");
- for (i = 0; i < maxuuids; i++) { - virSecretPtr sec = virSecretLookupByUUIDString(ctl->conn, uuids[i]); + for (i = 0; i < list->nsecrets; i++) { + virSecretPtr sec = list->secrets[i]; const char *usageType = NULL;
- if (!sec) { - VIR_FREE(uuids[i]); - continue; - } - switch (virSecretGetUsageType(sec)) { case VIR_SECRET_USAGE_TYPE_VOLUME: usageType = _("Volume"); break; }
+ char uuid[VIR_UUID_STRING_BUFLEN]; + if (virSecretGetUUIDString(list->secrets[i], uuid) < 0) { + vshError(ctl, "%s", _("Failed to get uuid of secret")); + goto cleanup; + } + if (usageType) { vshPrint(ctl, "%-36s %s %s\n", - uuids[i], usageType, + uuid, usageType, virSecretGetUsageID(sec)); } else { vshPrint(ctl, "%-36s %s\n", - uuids[i], _("Unused")); + uuid, _("Unused")); } - virSecretFree(sec); - VIR_FREE(uuids[i]); } - VIR_FREE(uuids); - return true; + + ret = true; + +cleanup: + vshSecretListFree(list); + return ret; }
const vshCmdDef secretCmds[] = {
Otherwise looks good. Peter

vshNameSorter now is not used anymore. Remove it. --- tools/virsh.c | 9 --------- tools/virsh.h | 1 - 2 files changed, 0 insertions(+), 10 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 684f7ca..8e794ea 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -136,15 +136,6 @@ _vshStrdup(vshControl *ctl, const char *s, const char *filename, int line) /* Poison the raw allocating identifiers in favor of our vsh variants. */ #define strdup use_vshStrdup_instead_of_strdup -int -vshNameSorter(const void *a, const void *b) -{ - const char **sa = (const char**)a; - const char **sb = (const char**)b; - - return vshStrcasecmp(*sa, *sb); -} - double vshPrettyCapacity(unsigned long long val, const char **unit) { diff --git a/tools/virsh.h b/tools/virsh.h index 2758d37..ac12b8b 100644 --- a/tools/virsh.h +++ b/tools/virsh.h @@ -314,7 +314,6 @@ void vshDebug(vshControl *ctl, int level, const char *format, ...) /* User visible sort, so we want locale-specific case comparison. */ # define vshStrcasecmp(S1, S2) strcasecmp(S1, S2) -int vshNameSorter(const void *a, const void *b); int vshDomainState(vshControl *ctl, virDomainPtr dom, int *reason); virTypedParameterPtr vshFindTypedParamByName(const char *name, -- 1.7.7.3

On 09/05/12 08:28, Osier Yang wrote:
vshNameSorter now is not used anymore. Remove it. --- tools/virsh.c | 9 --------- tools/virsh.h | 1 - 2 files changed, 0 insertions(+), 10 deletions(-)
Yep, this function isn't used after all the changes. ACK. Peter

The series looks fine and I'm giving ACK if you fix problems pointed out in the patches or other that may emerge. This API is a nice unification to the listing approach as there are no "inactive" secrets there's no race this would fix. Peter

On 09/05/2012 09:03 AM, Peter Krempa wrote:
The series looks fine and I'm giving ACK if you fix problems pointed out in the patches or other that may emerge.
This API is a nice unification to the listing approach as there are no "inactive" secrets there's no race this would fix.
Additionally, adding flags to filter on just ephemeral or private secrets will make this more powerful, but needs to be flowed through to more virsh flags. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
participants (3)
-
Eric Blake
-
Osier Yang
-
Peter Krempa