Merge "Add Secret Stores API support to Key Manager"
This commit is contained in:
@@ -37,3 +37,11 @@ Order Operations
|
||||
:noindex:
|
||||
:members: create_order, update_order, delete_order, get_order,
|
||||
find_order, orders
|
||||
|
||||
Secret Store Operations
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. autoclass:: openstack.key_manager.v1._proxy.Proxy
|
||||
:noindex:
|
||||
:members: secret_stores, get_global_default_secret_store,
|
||||
get_preferred_secret_store
|
||||
|
@@ -7,3 +7,4 @@ KeyManager Resources
|
||||
v1/container
|
||||
v1/order
|
||||
v1/secret
|
||||
v1/secret_store
|
||||
|
12
doc/source/user/resources/key_manager/v1/secret_store.rst
Normal file
12
doc/source/user/resources/key_manager/v1/secret_store.rst
Normal file
@@ -0,0 +1,12 @@
|
||||
openstack.key_manager.v1.secret_store
|
||||
=====================================
|
||||
|
||||
.. automodule:: openstack.key_manager.v1.secret_store
|
||||
|
||||
The SecretStore Class
|
||||
---------------------
|
||||
|
||||
The ``SecretStore`` class inherits from :class:`~openstack.resource.Resource`.
|
||||
|
||||
.. autoclass:: openstack.key_manager.v1.secret_store.SecretStore
|
||||
:members:
|
@@ -15,6 +15,7 @@ import typing as ty
|
||||
from openstack.key_manager.v1 import container as _container
|
||||
from openstack.key_manager.v1 import order as _order
|
||||
from openstack.key_manager.v1 import secret as _secret
|
||||
from openstack.key_manager.v1 import secret_store as _secret_store
|
||||
from openstack import proxy
|
||||
from openstack import resource
|
||||
|
||||
@@ -24,6 +25,7 @@ class Proxy(proxy.Proxy):
|
||||
"container": _container.Container,
|
||||
"order": _order.Order,
|
||||
"secret": _secret.Secret,
|
||||
"secret_store": _secret_store.SecretStore,
|
||||
}
|
||||
|
||||
def create_container(self, **attrs):
|
||||
@@ -270,6 +272,47 @@ class Proxy(proxy.Proxy):
|
||||
"""
|
||||
return self._update(_secret.Secret, secret, **attrs)
|
||||
|
||||
# ========== Secret Store Operations ==========
|
||||
|
||||
def secret_stores(self, **query):
|
||||
"""Return a generator of secret stores
|
||||
|
||||
:param kwargs query: Optional query parameters to be sent to limit
|
||||
the resources being returned.
|
||||
|
||||
:returns: A generator of secret store objects
|
||||
:rtype: :class:`~openstack.key_manager.v1.secret_store.SecretStore`
|
||||
"""
|
||||
return self._list(_secret_store.SecretStore, **query)
|
||||
|
||||
def get_global_default_secret_store(self):
|
||||
"""Get the global default secret store
|
||||
|
||||
:returns: One :class:`~openstack.key_manager.v1.secret_store.SecretStore`
|
||||
:raises: :class:`~openstack.exceptions.NotFoundException`
|
||||
when no resource can be found.
|
||||
"""
|
||||
return self._get(
|
||||
_secret_store.SecretStore,
|
||||
None,
|
||||
requires_id=False,
|
||||
base_path='/secret-stores/global-default',
|
||||
)
|
||||
|
||||
def get_preferred_secret_store(self):
|
||||
"""Get the preferred secret store for the current project
|
||||
|
||||
:returns: One :class:`~openstack.key_manager.v1.secret_store.SecretStore`
|
||||
:raises: :class:`~openstack.exceptions.NotFoundException`
|
||||
when no resource can be found.
|
||||
"""
|
||||
return self._get(
|
||||
_secret_store.SecretStore,
|
||||
None,
|
||||
requires_id=False,
|
||||
base_path='/secret-stores/preferred',
|
||||
)
|
||||
|
||||
# ========== Utilities ==========
|
||||
|
||||
def wait_for_status(
|
||||
|
58
openstack/key_manager/v1/secret_store.py
Normal file
58
openstack/key_manager/v1/secret_store.py
Normal file
@@ -0,0 +1,58 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from openstack.key_manager.v1 import _format
|
||||
from openstack import resource
|
||||
|
||||
|
||||
class SecretStore(resource.Resource):
|
||||
resources_key = 'secret_stores'
|
||||
base_path = '/secret-stores'
|
||||
|
||||
# capabilities
|
||||
allow_create = False
|
||||
allow_fetch = True
|
||||
allow_commit = False
|
||||
allow_delete = False
|
||||
allow_list = True
|
||||
|
||||
_query_mapping = resource.QueryParameters(
|
||||
"name",
|
||||
"status",
|
||||
"global_default",
|
||||
"crypto_plugin",
|
||||
"secret_store_plugin",
|
||||
"created",
|
||||
"updated",
|
||||
)
|
||||
|
||||
# Properties
|
||||
#: The name of the secret store
|
||||
name = resource.Body('name')
|
||||
#: The status of the secret store
|
||||
status = resource.Body('status')
|
||||
#: Timestamp of when the secret store was created
|
||||
created_at = resource.Body('created')
|
||||
#: Timestamp of when the secret store was last updated
|
||||
updated_at = resource.Body('updated')
|
||||
#: A URI to the secret store
|
||||
secret_store_ref = resource.Body('secret_store_ref')
|
||||
#: The ID of the secret store
|
||||
secret_store_id = resource.Body(
|
||||
'secret_store_ref', alternate_id=True, type=_format.HREFToUUID
|
||||
)
|
||||
#: Flag indicating if this secret store is global default
|
||||
global_default = resource.Body('global_default', type=bool)
|
||||
#: The crypto plugin name
|
||||
crypto_plugin = resource.Body('crypto_plugin')
|
||||
#: The secret store plugin name
|
||||
secret_store_plugin = resource.Body('secret_store_plugin')
|
0
openstack/tests/functional/key_manager/__init__.py
Normal file
0
openstack/tests/functional/key_manager/__init__.py
Normal file
@@ -0,0 +1,55 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from openstack.key_manager.v1 import secret_store as _secret_store
|
||||
from openstack.tests.functional import base
|
||||
|
||||
|
||||
class TestSecretStore(base.BaseFunctionalTest):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.require_service('key-manager')
|
||||
|
||||
def test_secret_store(self):
|
||||
"""Test Secret Store operations"""
|
||||
key_manager = self.operator_cloud.key_manager
|
||||
|
||||
# Test list secret stores
|
||||
secret_stores = list(key_manager.secret_stores())
|
||||
self.assertIsInstance(secret_stores, list)
|
||||
|
||||
for store in secret_stores:
|
||||
self.assertIsInstance(store, _secret_store.SecretStore)
|
||||
self.assertIsNotNone(store.name)
|
||||
self.assertIsNotNone(store.status)
|
||||
|
||||
# Test list secret stores with filters
|
||||
global_default_stores = list(
|
||||
key_manager.secret_stores(global_default=True)
|
||||
)
|
||||
self.assertIsInstance(global_default_stores, list)
|
||||
|
||||
active_stores = list(key_manager.secret_stores(status="ACTIVE"))
|
||||
self.assertIsInstance(active_stores, list)
|
||||
|
||||
# Test get global default secret store
|
||||
if global_default_stores:
|
||||
default_store = key_manager.get_global_default_secret_store()
|
||||
self.assertIsInstance(default_store, _secret_store.SecretStore)
|
||||
self.assertIsNotNone(default_store.name)
|
||||
self.assertTrue(default_store.global_default)
|
||||
|
||||
# Test get preferred secret store
|
||||
if secret_stores:
|
||||
preferred_store = key_manager.get_preferred_secret_store()
|
||||
self.assertIsInstance(preferred_store, _secret_store.SecretStore)
|
||||
self.assertIsNotNone(preferred_store.name)
|
@@ -14,6 +14,7 @@ from openstack.key_manager.v1 import _proxy
|
||||
from openstack.key_manager.v1 import container
|
||||
from openstack.key_manager.v1 import order
|
||||
from openstack.key_manager.v1 import secret
|
||||
from openstack.key_manager.v1 import secret_store
|
||||
from openstack.tests.unit import test_proxy_base
|
||||
|
||||
|
||||
@@ -97,3 +98,8 @@ class TestKeyManagerSecret(TestKeyManagerProxy):
|
||||
|
||||
def test_secret_update(self):
|
||||
self.verify_update(self.proxy.update_secret, secret.Secret)
|
||||
|
||||
|
||||
class TestKeyManagerSecretStore(TestKeyManagerProxy):
|
||||
def test_secret_stores(self):
|
||||
self.verify_list(self.proxy.secret_stores, secret_store.SecretStore)
|
||||
|
55
openstack/tests/unit/key_manager/v1/test_secret_store.py
Normal file
55
openstack/tests/unit/key_manager/v1/test_secret_store.py
Normal file
@@ -0,0 +1,55 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from openstack.key_manager.v1 import secret_store
|
||||
from openstack.tests.unit import base
|
||||
|
||||
|
||||
EXAMPLE = {
|
||||
"status": "ACTIVE",
|
||||
"updated": "2016-08-22T23:46:45.114283",
|
||||
"name": "PKCS11 HSM",
|
||||
"created": "2016-08-22T23:46:45.114283",
|
||||
"secret_store_ref": "http://localhost:9311/v1/secret-stores/4d27b7a7-b82f-491d-88c0-746bd67dadc8",
|
||||
"global_default": True,
|
||||
"crypto_plugin": "p11_crypto",
|
||||
"secret_store_plugin": "store_crypto",
|
||||
}
|
||||
|
||||
|
||||
class TestSecretStore(base.TestCase):
|
||||
def test_basic(self):
|
||||
sot = secret_store.SecretStore()
|
||||
self.assertEqual('secret_stores', sot.resources_key)
|
||||
self.assertEqual('/secret-stores', sot.base_path)
|
||||
self.assertFalse(sot.allow_create)
|
||||
self.assertTrue(sot.allow_fetch)
|
||||
self.assertFalse(sot.allow_commit)
|
||||
self.assertFalse(sot.allow_delete)
|
||||
self.assertTrue(sot.allow_list)
|
||||
|
||||
def test_make_it(self):
|
||||
sot = secret_store.SecretStore(**EXAMPLE)
|
||||
self.assertEqual(EXAMPLE['name'], sot.name)
|
||||
self.assertEqual(EXAMPLE['status'], sot.status)
|
||||
self.assertEqual(EXAMPLE['created'], sot.created_at)
|
||||
self.assertEqual(EXAMPLE['updated'], sot.updated_at)
|
||||
self.assertEqual(EXAMPLE['secret_store_ref'], sot.secret_store_ref)
|
||||
self.assertEqual(EXAMPLE['global_default'], sot.global_default)
|
||||
self.assertEqual(EXAMPLE['crypto_plugin'], sot.crypto_plugin)
|
||||
self.assertEqual(
|
||||
EXAMPLE['secret_store_plugin'], sot.secret_store_plugin
|
||||
)
|
||||
# Test the alternate_id extraction
|
||||
self.assertEqual(
|
||||
'4d27b7a7-b82f-491d-88c0-746bd67dadc8', sot.secret_store_id
|
||||
)
|
Reference in New Issue
Block a user