Refactor Key Manager for resource2
This change updates the Key Manager service for the resource2/proxy2 refactoring. Along with making it work with the new classes, it improves usability--at least temporarily--by exposing the ID value necessary from the HREFs that the service returns. The HREF that gets returned, e.g., from a list call, is not directly usable to then pass it into a get call. A more long-term fix for this would potentially be to create a Key Manager specific base class that fiddles around with IDs and looks to see if they are an HREF and converts them to a UUID in the proper direction depending on where the data is going, but that's too much to tackle in this refactoring change. Besides updating some of the resources to match the documented attributes, one feature this does add is retrieval of the Secret payload, which is done via a separate endpoint. However, like other calls in Glance and Heat, we unify them in the proxy's `get_secret` call so the user doesn't need to know it's a separate call. This also includes some basic docs in the user guide to show how the different ID usage is currently necessary. Change-Id: I8b5753e121d8f79350b38803e8aac95d7b4d1627
This commit is contained in:
parent
ce8e5141e4
commit
0a19263fac
|
@ -6,4 +6,51 @@ connection to your OpenStack cloud by following the :doc:`connect` user
|
|||
guide. This will provide you with the ``conn`` variable used in the examples
|
||||
below.
|
||||
|
||||
.. TODO(thowe): Implement this guide
|
||||
.. contents:: Table of Contents
|
||||
:local:
|
||||
|
||||
.. note:: Some interactions with the Key Manager service differ from that
|
||||
of other services in that resources do not have a proper ``id`` parameter,
|
||||
which is necessary to make some calls. Instead, resources have a separately
|
||||
named id attribute, e.g., the Secret resource has ``secret_id``.
|
||||
|
||||
The examples below outline when to pass in those id values.
|
||||
|
||||
Create a Secret
|
||||
---------------
|
||||
|
||||
The Key Manager service allows you to create new secrets by passing the
|
||||
attributes of the :class:`~openstack.key_manager.v1.secret.Secret` to the
|
||||
:meth:`~openstack.key_manager.v1._proxy.Proxy.create_secret` method.
|
||||
|
||||
.. literalinclude:: ../examples/key_manager/create.py
|
||||
:pyobject: create_secret
|
||||
|
||||
List Secrets
|
||||
------------
|
||||
|
||||
Once you have stored some secrets, they are available for you to list
|
||||
via the :meth:`~openstack.key_manager.v1._proxy.Proxy.secrets` method.
|
||||
This method returns a generator, which yields each
|
||||
:class:`~openstack.key_manager.v1.secret.Secret`.
|
||||
|
||||
.. literalinclude:: ../examples/key_manager/list.py
|
||||
:pyobject: list_secrets
|
||||
|
||||
The :meth:`~openstack.key_manager.v1._proxy.Proxy.secrets` method can
|
||||
also make more advanced queries to limit the secrets that are returned.
|
||||
|
||||
.. literalinclude:: ../examples/key_manager/list.py
|
||||
:pyobject: list_secrets_query
|
||||
|
||||
Get Secret Payload
|
||||
------------------
|
||||
|
||||
Once you have received a :class:`~openstack.key_manager.v1.secret.Secret`,
|
||||
you can obtain the payload for it by passing the secret's id value to
|
||||
the :meth:`~openstack.key_manager.v1._proxy.Proxy.secrets` method.
|
||||
Use the :data:`~openstack.key_manager.v1.secret.Secret.secret_id` attribute
|
||||
when making this request.
|
||||
|
||||
.. literalinclude:: ../examples/key_manager/get.py
|
||||
:pyobject: get_secret_payload
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# 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.
|
||||
|
||||
"""
|
||||
List resources from the Key Manager service.
|
||||
"""
|
||||
|
||||
|
||||
def create_secret(conn):
|
||||
print("Create a secret:")
|
||||
|
||||
conn.key_manager.create_secret(name="My public key",
|
||||
secret_type="public",
|
||||
expiration="2020-02-28T23:59:59",
|
||||
payload="ssh rsa...",
|
||||
payload_content_type="text/plain")
|
|
@ -0,0 +1,26 @@
|
|||
# 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.
|
||||
|
||||
"""
|
||||
List resources from the Key Manager service.
|
||||
"""
|
||||
|
||||
s = None
|
||||
|
||||
|
||||
def get_secret_payload(conn):
|
||||
print("Get a secret's payload:")
|
||||
|
||||
# Assuming you have an object `s` which you perhaps received from
|
||||
# a conn.key_manager.secrets() call...
|
||||
secret = conn.key_manager.get_secret(s.secret_id)
|
||||
print(secret.payload)
|
|
@ -0,0 +1,31 @@
|
|||
# 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.
|
||||
|
||||
"""
|
||||
List resources from the Key Manager service.
|
||||
"""
|
||||
|
||||
|
||||
def list_secrets(conn):
|
||||
print("List Secrets:")
|
||||
|
||||
for secret in conn.key_manager.secrets():
|
||||
print(secret)
|
||||
|
||||
|
||||
def list_secrets_query(conn):
|
||||
print("List Secrets:")
|
||||
|
||||
for secret in conn.key_manager.secrets(
|
||||
secret_type="symmetric",
|
||||
expiration="gte:2020-01-01T00:00:00"):
|
||||
print(secret)
|
|
@ -0,0 +1,39 @@
|
|||
# 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 import format
|
||||
|
||||
from six.moves.urllib import parse
|
||||
|
||||
|
||||
class HREFToUUID(format.Formatter):
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, value):
|
||||
"""Convert a HREF to the UUID portion"""
|
||||
parts = parse.urlsplit(value)
|
||||
|
||||
# Only try to proceed if we have an actual URI.
|
||||
# Just check that we have a scheme, netloc, and path.
|
||||
if not all(parts[:3]):
|
||||
raise ValueError("Unable to convert %s to an ID" % value)
|
||||
|
||||
# The UUID will be the last portion of the URI.
|
||||
return parts.path.split("/")[-1]
|
||||
|
||||
@classmethod
|
||||
def serialize(cls, value):
|
||||
# NOTE(briancurtin): If we had access to the session to get
|
||||
# the endpoint we could do something smart here like take an ID
|
||||
# and give back an HREF, but this will just have to be something
|
||||
# that works different because Barbican does what it does...
|
||||
return value
|
|
@ -13,10 +13,10 @@
|
|||
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 import proxy
|
||||
from openstack import proxy2
|
||||
|
||||
|
||||
class Proxy(proxy.BaseProxy):
|
||||
class Proxy(proxy2.BaseProxy):
|
||||
|
||||
def create_container(self, **attrs):
|
||||
"""Create a new container from attributes
|
||||
|
|
|
@ -11,34 +11,39 @@
|
|||
# under the License.
|
||||
|
||||
from openstack.key_manager import key_manager_service
|
||||
from openstack import resource
|
||||
from openstack.key_manager.v1 import _format
|
||||
from openstack import resource2
|
||||
|
||||
|
||||
class Container(resource.Resource):
|
||||
id_attribute = 'container_ref'
|
||||
class Container(resource2.Resource):
|
||||
resources_key = 'containers'
|
||||
base_path = '/containers'
|
||||
service = key_manager_service.KeyManagerService()
|
||||
|
||||
# capabilities
|
||||
allow_create = True
|
||||
allow_retrieve = True
|
||||
allow_get = True
|
||||
allow_update = True
|
||||
allow_delete = True
|
||||
allow_list = True
|
||||
|
||||
# Properties
|
||||
#: A URI for this container
|
||||
container_ref = resource.prop('container_ref')
|
||||
container_ref = resource2.Body('container_ref')
|
||||
#: The ID for this container
|
||||
container_id = resource2.Body('container_ref', alternate_id=True,
|
||||
type=_format.HREFToUUID)
|
||||
#: The timestamp when this container was created.
|
||||
created_at = resource.prop('created')
|
||||
created_at = resource2.Body('created')
|
||||
#: The name of this container
|
||||
name = resource.prop('name')
|
||||
name = resource2.Body('name')
|
||||
#: A list of references to secrets in this container
|
||||
secret_refs = resource.prop('secret_refs')
|
||||
secret_refs = resource2.Body('secret_refs', type=list)
|
||||
#: The status of this container
|
||||
status = resource.prop('status')
|
||||
status = resource2.Body('status')
|
||||
#: The type of this container
|
||||
type = resource.prop('type')
|
||||
type = resource2.Body('type')
|
||||
#: The timestamp when this container was updated.
|
||||
updated_at = resource.prop('updated')
|
||||
updated_at = resource2.Body('updated')
|
||||
#: A party interested in this container.
|
||||
consumers = resource2.Body('consumers', type=list)
|
||||
|
|
|
@ -11,34 +11,45 @@
|
|||
# under the License.
|
||||
|
||||
from openstack.key_manager import key_manager_service
|
||||
from openstack import resource
|
||||
from openstack.key_manager.v1 import _format
|
||||
from openstack import resource2
|
||||
|
||||
|
||||
class Order(resource.Resource):
|
||||
class Order(resource2.Resource):
|
||||
resources_key = 'orders'
|
||||
base_path = '/orders'
|
||||
service = key_manager_service.KeyManagerService()
|
||||
|
||||
# capabilities
|
||||
allow_create = True
|
||||
allow_retrieve = True
|
||||
allow_get = True
|
||||
allow_update = True
|
||||
allow_delete = True
|
||||
allow_list = True
|
||||
|
||||
# Properties
|
||||
# TODO(briancurtin): not documented
|
||||
error_reason = resource.prop('error_reason')
|
||||
# TODO(briancurtin): not documented
|
||||
error_status_code = resource.prop('error_status_code')
|
||||
#: a dictionary containing key-value parameters which specify the
|
||||
#: Timestamp in ISO8601 format of when the order was created
|
||||
created_at = resource2.Body('created')
|
||||
#: Keystone Id of the user who created the order
|
||||
creator_id = resource2.Body('creator_id')
|
||||
#: A dictionary containing key-value parameters which specify the
|
||||
#: details of an order request
|
||||
meta = resource.prop('meta')
|
||||
meta = resource2.Body('meta', type=dict)
|
||||
#: A URI for this order
|
||||
order_ref = resource.prop('order_ref')
|
||||
#: TODO(briancurtin): not documented
|
||||
secret_ref = resource.prop('secret_ref')
|
||||
order_ref = resource2.Body('order_ref')
|
||||
#: The ID of this order
|
||||
order_id = resource2.Body('order_ref', alternate_id=True,
|
||||
type=_format.HREFToUUID)
|
||||
#: Secret href associated with the order
|
||||
secret_ref = resource2.Body('secret_ref')
|
||||
#: Secret ID associated with the order
|
||||
secret_id = resource2.Body('secret_ref', type=_format.HREFToUUID)
|
||||
# The status of this order
|
||||
status = resource.prop('status')
|
||||
status = resource2.Body('status')
|
||||
#: Metadata associated with the order
|
||||
sub_status = resource2.Body('sub_status')
|
||||
#: Metadata associated with the order
|
||||
sub_status_message = resource2.Body('sub_status_message')
|
||||
# The type of order
|
||||
type = resource.prop('type')
|
||||
type = resource2.Body('type')
|
||||
#: Timestamp in ISO8601 format of the last time the order was updated.
|
||||
updated_at = resource2.Body('updated')
|
||||
|
|
|
@ -11,39 +11,96 @@
|
|||
# under the License.
|
||||
|
||||
from openstack.key_manager import key_manager_service
|
||||
from openstack import resource
|
||||
from openstack.key_manager.v1 import _format
|
||||
from openstack import resource2
|
||||
from openstack import utils
|
||||
|
||||
|
||||
class Secret(resource.Resource):
|
||||
id_attribute = 'secret_ref'
|
||||
class Secret(resource2.Resource):
|
||||
resources_key = 'secrets'
|
||||
base_path = '/secrets'
|
||||
service = key_manager_service.KeyManagerService()
|
||||
|
||||
# capabilities
|
||||
allow_create = True
|
||||
allow_retrieve = True
|
||||
allow_get = True
|
||||
allow_update = True
|
||||
allow_delete = True
|
||||
allow_list = True
|
||||
|
||||
_query_mapping = resource2.QueryParameters("name", "mode", "bits",
|
||||
"secret_type", "acl_only",
|
||||
"created", "updated",
|
||||
"expiration", "sort",
|
||||
algorithm="alg")
|
||||
|
||||
# Properties
|
||||
#: Metadata provided by a user or system for informational purposes
|
||||
algorithm = resource.prop('algorithm')
|
||||
algorithm = resource2.Body('algorithm')
|
||||
#: Metadata provided by a user or system for informational purposes.
|
||||
#: Value must be greater than zero.
|
||||
bit_length = resource.prop('bit_length')
|
||||
bit_length = resource2.Body('bit_length')
|
||||
#: A list of content types
|
||||
content_types = resource.prop('content_types')
|
||||
content_types = resource2.Body('content_types', type=dict)
|
||||
#: Once this timestamp has past, the secret will no longer be available.
|
||||
expires_at = resource.prop('expiration')
|
||||
expires_at = resource2.Body('expiration')
|
||||
#: Timestamp of when the secret was created.
|
||||
created_at = resource2.Body('created')
|
||||
#: Timestamp of when the secret was last updated.
|
||||
updated_at = resource2.Body('updated')
|
||||
#: The type/mode of the algorithm associated with the secret information.
|
||||
mode = resource.prop('mode')
|
||||
mode = resource2.Body('mode')
|
||||
#: The name of the secret set by the user
|
||||
name = resource.prop('name')
|
||||
name = resource2.Body('name')
|
||||
#: A URI to the sercret
|
||||
secret_ref = resource.prop('secret_ref')
|
||||
secret_ref = resource2.Body('secret_ref')
|
||||
#: The ID of the secret
|
||||
# NOTE: This is not really how alternate IDs are supposed to work and
|
||||
# ultimately means this has to work differently than all other services
|
||||
# in all of OpenStack because of the departure from using actual IDs
|
||||
# that even this service can't even use itself.
|
||||
secret_id = resource2.Body('secret_ref', alternate_id=True,
|
||||
type=_format.HREFToUUID)
|
||||
#: Used to indicate the type of secret being stored.
|
||||
secret_type = resource2.Body('secret_type')
|
||||
#: The status of this secret
|
||||
status = resource.prop('status')
|
||||
status = resource2.Body('status')
|
||||
#: A timestamp when this secret was updated.
|
||||
updated_at = resource.prop('updated')
|
||||
updated_at = resource2.Body('updated')
|
||||
#: The secret's data to be stored. payload_content_type must also
|
||||
#: be supplied if payload is included. (optional)
|
||||
payload = resource2.Body('payload')
|
||||
#: The media type for the content of the payload.
|
||||
#: (required if payload is included)
|
||||
payload_content_type = resource2.Body('payload_content_type')
|
||||
#: The encoding used for the payload to be able to include it in
|
||||
#: the JSON request. Currently only base64 is supported.
|
||||
#: (required if payload is encoded)
|
||||
payload_content_encoding = resource2.Body('payload_content_encoding')
|
||||
|
||||
def get(self, session, requires_id=True):
|
||||
request = self._prepare_request(requires_id=requires_id)
|
||||
|
||||
response = session.get(request.uri,
|
||||
endpoint_filter=self.service).json()
|
||||
|
||||
content_type = None
|
||||
if self.payload_content_type is not None:
|
||||
content_type = self.payload_content_type
|
||||
elif "content_types" in response:
|
||||
content_type = response["content_types"]["default"]
|
||||
|
||||
# Only try to get the payload if a content type has been explicitly
|
||||
# specified or if one was found in the metadata response
|
||||
if content_type is not None:
|
||||
payload = session.get(utils.urljoin(request.uri, "payload"),
|
||||
endpoint_filter=self.service,
|
||||
headers={"Accept": content_type})
|
||||
response["payload"] = payload.text
|
||||
|
||||
# We already have the JSON here so don't call into _translate_response
|
||||
body = self._filter_component(response, self._body_mapping())
|
||||
self._body.attributes.update(body)
|
||||
self._body.clean()
|
||||
|
||||
return self
|
||||
|
|
|
@ -14,15 +14,17 @@ import testtools
|
|||
|
||||
from openstack.key_manager.v1 import container
|
||||
|
||||
IDENTIFIER = 'http://localhost/containers/IDENTIFIER'
|
||||
ID_VAL = "123"
|
||||
IDENTIFIER = 'http://localhost/containers/%s' % ID_VAL
|
||||
EXAMPLE = {
|
||||
'container_ref': IDENTIFIER,
|
||||
'created': '2015-03-09T12:14:57.233772',
|
||||
'name': '3',
|
||||
'secret_refs': '4',
|
||||
'secret_refs': ['4'],
|
||||
'status': '5',
|
||||
'type': '6',
|
||||
'updated': '2015-03-09T12:15:57.233772',
|
||||
'consumers': ['7']
|
||||
}
|
||||
|
||||
|
||||
|
@ -35,14 +37,13 @@ class TestContainer(testtools.TestCase):
|
|||
self.assertEqual('/containers', sot.base_path)
|
||||
self.assertEqual('key-manager', sot.service.service_type)
|
||||
self.assertTrue(sot.allow_create)
|
||||
self.assertTrue(sot.allow_retrieve)
|
||||
self.assertTrue(sot.allow_get)
|
||||
self.assertTrue(sot.allow_update)
|
||||
self.assertTrue(sot.allow_delete)
|
||||
self.assertTrue(sot.allow_list)
|
||||
|
||||
def test_make_it(self):
|
||||
sot = container.Container(EXAMPLE)
|
||||
self.assertEqual(EXAMPLE['container_ref'], sot.container_ref)
|
||||
sot = container.Container(**EXAMPLE)
|
||||
self.assertEqual(EXAMPLE['created'], sot.created_at)
|
||||
self.assertEqual(EXAMPLE['name'], sot.name)
|
||||
self.assertEqual(EXAMPLE['secret_refs'], sot.secret_refs)
|
||||
|
@ -50,3 +51,6 @@ class TestContainer(testtools.TestCase):
|
|||
self.assertEqual(EXAMPLE['type'], sot.type)
|
||||
self.assertEqual(EXAMPLE['updated'], sot.updated_at)
|
||||
self.assertEqual(EXAMPLE['container_ref'], sot.id)
|
||||
self.assertEqual(EXAMPLE['container_ref'], sot.container_ref)
|
||||
self.assertEqual(ID_VAL, sot.container_id)
|
||||
self.assertEqual(EXAMPLE['consumers'], sot.consumers)
|
||||
|
|
|
@ -14,15 +14,20 @@ import testtools
|
|||
|
||||
from openstack.key_manager.v1 import order
|
||||
|
||||
IDENTIFIER = 'IDENTIFIER'
|
||||
ID_VAL = "123"
|
||||
SECRET_ID = "5"
|
||||
IDENTIFIER = 'http://localhost/orders/%s' % ID_VAL
|
||||
EXAMPLE = {
|
||||
'error_reason': '1',
|
||||
'error_status_code': '2',
|
||||
'meta': '3',
|
||||
'order_ref': '4',
|
||||
'secret_ref': '5',
|
||||
'created': '1',
|
||||
'creator_id': '2',
|
||||
'meta': {'key': '3'},
|
||||
'order_ref': IDENTIFIER,
|
||||
'secret_ref': 'http://localhost/secrets/%s' % SECRET_ID,
|
||||
'status': '6',
|
||||
'type': '7',
|
||||
'sub_status': '7',
|
||||
'sub_status_message': '8',
|
||||
'type': '9',
|
||||
'updated': '10'
|
||||
}
|
||||
|
||||
|
||||
|
@ -35,17 +40,22 @@ class TestOrder(testtools.TestCase):
|
|||
self.assertEqual('/orders', sot.base_path)
|
||||
self.assertEqual('key-manager', sot.service.service_type)
|
||||
self.assertTrue(sot.allow_create)
|
||||
self.assertTrue(sot.allow_retrieve)
|
||||
self.assertTrue(sot.allow_get)
|
||||
self.assertTrue(sot.allow_update)
|
||||
self.assertTrue(sot.allow_delete)
|
||||
self.assertTrue(sot.allow_list)
|
||||
|
||||
def test_make_it(self):
|
||||
sot = order.Order(EXAMPLE)
|
||||
self.assertEqual(EXAMPLE['error_reason'], sot.error_reason)
|
||||
self.assertEqual(EXAMPLE['error_status_code'], sot.error_status_code)
|
||||
sot = order.Order(**EXAMPLE)
|
||||
self.assertEqual(EXAMPLE['created'], sot.created_at)
|
||||
self.assertEqual(EXAMPLE['creator_id'], sot.creator_id)
|
||||
self.assertEqual(EXAMPLE['meta'], sot.meta)
|
||||
self.assertEqual(EXAMPLE['order_ref'], sot.order_ref)
|
||||
self.assertEqual(ID_VAL, sot.order_id)
|
||||
self.assertEqual(EXAMPLE['secret_ref'], sot.secret_ref)
|
||||
self.assertEqual(SECRET_ID, sot.secret_id)
|
||||
self.assertEqual(EXAMPLE['status'], sot.status)
|
||||
self.assertEqual(EXAMPLE['sub_status'], sot.sub_status)
|
||||
self.assertEqual(EXAMPLE['sub_status_message'], sot.sub_status_message)
|
||||
self.assertEqual(EXAMPLE['type'], sot.type)
|
||||
self.assertEqual(EXAMPLE['updated'], sot.updated_at)
|
||||
|
|
|
@ -14,12 +14,12 @@ 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.tests.unit import test_proxy_base
|
||||
from openstack.tests.unit import test_proxy_base2
|
||||
|
||||
|
||||
class TestKeyManagementProxy(test_proxy_base.TestProxyBase):
|
||||
class TestKeyManagerProxy(test_proxy_base2.TestProxyBase):
|
||||
def setUp(self):
|
||||
super(TestKeyManagementProxy, self).setUp()
|
||||
super(TestKeyManagerProxy, self).setUp()
|
||||
self.proxy = _proxy.Proxy(self.session)
|
||||
|
||||
def test_server_create_attrs(self):
|
||||
|
|
|
@ -10,21 +10,28 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
import testtools
|
||||
|
||||
from openstack.key_manager.v1 import secret
|
||||
|
||||
IDENTIFIER = 'http://localhost:9311/v1/secrets/ID'
|
||||
ID_VAL = "123"
|
||||
IDENTIFIER = 'http://localhost:9311/v1/secrets/%s' % ID_VAL
|
||||
EXAMPLE = {
|
||||
'algorithm': '1',
|
||||
'bit_length': '2',
|
||||
'content_types': '3',
|
||||
'content_types': {'default': '3'},
|
||||
'expiration': '2017-03-09T12:14:57.233772',
|
||||
'mode': '5',
|
||||
'name': '6',
|
||||
'secret_ref': IDENTIFIER,
|
||||
'status': '8',
|
||||
'updated': '2015-03-09T12:15:57.233772',
|
||||
'updated': '2015-03-09T12:15:57.233773',
|
||||
'created': '2015-03-09T12:15:57.233774',
|
||||
'secret_type': '9',
|
||||
'payload': '10',
|
||||
'payload_content_type': '11',
|
||||
'payload_content_encoding': '12'
|
||||
}
|
||||
|
||||
|
||||
|
@ -37,13 +44,25 @@ class TestSecret(testtools.TestCase):
|
|||
self.assertEqual('/secrets', sot.base_path)
|
||||
self.assertEqual('key-manager', sot.service.service_type)
|
||||
self.assertTrue(sot.allow_create)
|
||||
self.assertTrue(sot.allow_retrieve)
|
||||
self.assertTrue(sot.allow_get)
|
||||
self.assertTrue(sot.allow_update)
|
||||
self.assertTrue(sot.allow_delete)
|
||||
self.assertTrue(sot.allow_list)
|
||||
|
||||
self.assertDictEqual({"name": "name",
|
||||
"mode": "mode",
|
||||
"bits": "bits",
|
||||
"secret_type": "secret_type",
|
||||
"acl_only": "acl_only",
|
||||
"created": "created",
|
||||
"updated": "updated",
|
||||
"expiration": "expiration",
|
||||
"sort": "sort",
|
||||
"algorithm": "alg"},
|
||||
sot._query_mapping._mapping)
|
||||
|
||||
def test_make_it(self):
|
||||
sot = secret.Secret(EXAMPLE)
|
||||
sot = secret.Secret(**EXAMPLE)
|
||||
self.assertEqual(EXAMPLE['algorithm'], sot.algorithm)
|
||||
self.assertEqual(EXAMPLE['bit_length'], sot.bit_length)
|
||||
self.assertEqual(EXAMPLE['content_types'], sot.content_types)
|
||||
|
@ -51,6 +70,64 @@ class TestSecret(testtools.TestCase):
|
|||
self.assertEqual(EXAMPLE['mode'], sot.mode)
|
||||
self.assertEqual(EXAMPLE['name'], sot.name)
|
||||
self.assertEqual(EXAMPLE['secret_ref'], sot.secret_ref)
|
||||
self.assertEqual(EXAMPLE['secret_ref'], sot.id)
|
||||
self.assertEqual(ID_VAL, sot.secret_id)
|
||||
self.assertEqual(EXAMPLE['status'], sot.status)
|
||||
self.assertEqual(EXAMPLE['updated'], sot.updated_at)
|
||||
self.assertEqual(EXAMPLE['secret_ref'], sot.id)
|
||||
self.assertEqual(EXAMPLE['secret_type'], sot.secret_type)
|
||||
self.assertEqual(EXAMPLE['payload'], sot.payload)
|
||||
self.assertEqual(EXAMPLE['payload_content_type'],
|
||||
sot.payload_content_type)
|
||||
self.assertEqual(EXAMPLE['payload_content_encoding'],
|
||||
sot.payload_content_encoding)
|
||||
|
||||
def test_get_no_payload(self):
|
||||
sot = secret.Secret(id="id")
|
||||
|
||||
sess = mock.Mock()
|
||||
rv = mock.Mock()
|
||||
return_body = {"status": "cool"}
|
||||
rv.json = mock.Mock(return_value=return_body)
|
||||
sess.get = mock.Mock(return_value=rv)
|
||||
|
||||
sot.get(sess)
|
||||
|
||||
sess.get.assert_called_once_with("secrets/id",
|
||||
endpoint_filter=sot.service)
|
||||
|
||||
def _test_payload(self, sot, metadata, content_type):
|
||||
content_type = "some/type"
|
||||
sot = secret.Secret(id="id", payload_content_type=content_type)
|
||||
|
||||
metadata_response = mock.Mock()
|
||||
metadata_response.json = mock.Mock(return_value=metadata)
|
||||
|
||||
payload_response = mock.Mock()
|
||||
payload = "secret info"
|
||||
payload_response.text = payload
|
||||
|
||||
sess = mock.Mock()
|
||||
sess.get = mock.Mock(side_effect=[metadata_response, payload_response])
|
||||
|
||||
rv = sot.get(sess)
|
||||
|
||||
sess.get.assert_has_calls(
|
||||
[mock.call("secrets/id", endpoint_filter=sot.service),
|
||||
mock.call("secrets/id/payload", endpoint_filter=sot.service,
|
||||
headers={"Accept": content_type})])
|
||||
|
||||
self.assertEqual(rv.payload, payload)
|
||||
self.assertEqual(rv.status, metadata["status"])
|
||||
|
||||
def test_get_with_payload_from_argument(self):
|
||||
metadata = {"status": "great"}
|
||||
content_type = "some/type"
|
||||
sot = secret.Secret(id="id", payload_content_type=content_type)
|
||||
self._test_payload(sot, metadata, content_type)
|
||||
|
||||
def test_get_with_payload_from_content_types(self):
|
||||
content_type = "some/type"
|
||||
metadata = {"status": "fine",
|
||||
"content_types": {"default": content_type}}
|
||||
sot = secret.Secret(id="id")
|
||||
self._test_payload(sot, metadata, content_type)
|
||||
|
|
Loading…
Reference in New Issue