Complete compute aggregate functions
In order to switch next part of OSC towards SDK we need to add some missing bits to the aggregates. Since this is another example when API returns 400 if we try accessing resource with name and it doesn't support - modify general behavior for also skipping 400 in the find method Change-Id: Ia6711b1c27514d0698fec1efedaefeeb93722b9d
This commit is contained in:
parent
599ef07775
commit
b60915aab3
@ -261,6 +261,20 @@ class Proxy(proxy.Proxy):
|
||||
"""
|
||||
return self._get(_aggregate.Aggregate, aggregate)
|
||||
|
||||
def find_aggregate(self, name_or_id, ignore_missing=True):
|
||||
"""Find a single aggregate
|
||||
|
||||
:param name_or_id: The name or ID of an aggregate.
|
||||
:param bool ignore_missing: When set to ``False``
|
||||
:class:`~openstack.exceptions.ResourceNotFound` will be raised when
|
||||
the resource does not exist. When set to ``True``, None will be
|
||||
returned when attempting to find a nonexistent resource.
|
||||
:returns: One :class:`~openstack.compute.v2.aggregate.Aggregate`
|
||||
or None
|
||||
"""
|
||||
return self._find(_aggregate.Aggregate, name_or_id,
|
||||
ignore_missing=ignore_missing)
|
||||
|
||||
def create_aggregate(self, **attrs):
|
||||
"""Create a new host aggregate from attributes
|
||||
|
||||
@ -345,6 +359,26 @@ class Proxy(proxy.Proxy):
|
||||
aggregate = self._get_resource(_aggregate.Aggregate, aggregate)
|
||||
return aggregate.set_metadata(self, metadata)
|
||||
|
||||
def aggregate_precache_images(self, aggregate, images):
|
||||
"""Requests image precaching on an aggregate
|
||||
|
||||
:param aggregate: Either the ID of a aggregate or a
|
||||
:class:`~openstack.compute.v2.aggregate.Aggregate` instance.
|
||||
:param images: Single image id or list of image ids.
|
||||
|
||||
:returns: ``None``
|
||||
"""
|
||||
aggregate = self._get_resource(_aggregate.Aggregate, aggregate)
|
||||
# We need to ensure we pass list of image IDs
|
||||
if isinstance(images, str):
|
||||
images = [images]
|
||||
image_data = []
|
||||
for img in images:
|
||||
image_data.append({'id': img})
|
||||
return aggregate.precache_images(self, image_data)
|
||||
|
||||
# ========== Images ==========
|
||||
|
||||
def delete_image(self, image, ignore_missing=True):
|
||||
"""Delete an image
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
from openstack import exceptions
|
||||
from openstack import resource
|
||||
from openstack import utils
|
||||
|
||||
@ -30,25 +30,31 @@ class Aggregate(resource.Resource):
|
||||
# Properties
|
||||
#: Availability zone of aggregate
|
||||
availability_zone = resource.Body('availability_zone')
|
||||
#: The date and time when the resource was created.
|
||||
created_at = resource.Body('created_at')
|
||||
#: The date and time when the resource was deleted.
|
||||
deleted_at = resource.Body('deleted_at')
|
||||
#: Deleted?
|
||||
deleted = resource.Body('deleted')
|
||||
is_deleted = resource.Body('deleted', type=bool)
|
||||
#: Name of aggregate
|
||||
name = resource.Body('name')
|
||||
#: Hosts
|
||||
hosts = resource.Body('hosts')
|
||||
hosts = resource.Body('hosts', type=list)
|
||||
#: Metadata
|
||||
metadata = resource.Body('metadata')
|
||||
metadata = resource.Body('metadata', type=dict)
|
||||
#: The date and time when the resource was updated
|
||||
updated_at = resource.Body('updated_at')
|
||||
#: UUID
|
||||
uuid = resource.Body('uuid')
|
||||
# uuid introduced in 2.41
|
||||
_max_microversion = '2.41'
|
||||
# Image pre-caching introduced in 2.81
|
||||
_max_microversion = '2.81'
|
||||
|
||||
def _action(self, session, body, microversion=None):
|
||||
"""Preform aggregate actions given the message body."""
|
||||
url = utils.urljoin(self.base_path, self.id, 'action')
|
||||
headers = {'Accept': ''}
|
||||
response = session.post(
|
||||
url, json=body, headers=headers, microversion=microversion)
|
||||
url, json=body, microversion=microversion)
|
||||
exceptions.raise_from_response(response)
|
||||
aggregate = Aggregate()
|
||||
aggregate._translate_response(response=response)
|
||||
return aggregate
|
||||
@ -67,3 +73,12 @@ class Aggregate(resource.Resource):
|
||||
"""Creates or replaces metadata for an aggregate."""
|
||||
body = {'set_metadata': {'metadata': metadata}}
|
||||
return self._action(session, body)
|
||||
|
||||
def precache_images(self, session, images):
|
||||
"""Requests image pre-caching"""
|
||||
body = {'cache': images}
|
||||
url = utils.urljoin(self.base_path, self.id, 'images')
|
||||
response = session.post(
|
||||
url, json=body, microversion=self._max_microversion)
|
||||
exceptions.raise_from_response(response)
|
||||
# This API has no result
|
||||
|
@ -1895,7 +1895,9 @@ class Resource(dict):
|
||||
connection=session._get_connection(),
|
||||
**params)
|
||||
return match.fetch(session, **params)
|
||||
except exceptions.NotFoundException:
|
||||
except (exceptions.NotFoundException, exceptions.BadRequestException):
|
||||
# NOTE(gtema): There are few places around openstack that return
|
||||
# 400 if we try to GET resource and it doesn't exist.
|
||||
pass
|
||||
|
||||
if ('name' in cls._query_mapping._mapping.keys()
|
||||
|
@ -60,7 +60,10 @@ class TestAggregate(base.TestCase):
|
||||
sot = aggregate.Aggregate(**EXAMPLE)
|
||||
self.assertEqual(EXAMPLE['name'], sot.name)
|
||||
self.assertEqual(EXAMPLE['availability_zone'], sot.availability_zone)
|
||||
self.assertEqual(EXAMPLE['deleted'], sot.deleted)
|
||||
self.assertEqual(EXAMPLE['deleted'], sot.is_deleted)
|
||||
self.assertEqual(EXAMPLE['deleted_at'], sot.deleted_at)
|
||||
self.assertEqual(EXAMPLE['created_at'], sot.created_at)
|
||||
self.assertEqual(EXAMPLE['updated_at'], sot.updated_at)
|
||||
self.assertEqual(EXAMPLE['hosts'], sot.hosts)
|
||||
self.assertEqual(EXAMPLE['id'], sot.id)
|
||||
self.assertEqual(EXAMPLE['uuid'], sot.uuid)
|
||||
@ -73,9 +76,8 @@ class TestAggregate(base.TestCase):
|
||||
|
||||
url = 'os-aggregates/4/action'
|
||||
body = {"add_host": {"host": "host1"}}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
url, json=body, microversion=None)
|
||||
|
||||
def test_remove_host(self):
|
||||
sot = aggregate.Aggregate(**EXAMPLE)
|
||||
@ -84,9 +86,8 @@ class TestAggregate(base.TestCase):
|
||||
|
||||
url = 'os-aggregates/4/action'
|
||||
body = {"remove_host": {"host": "host1"}}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
url, json=body, microversion=None)
|
||||
|
||||
def test_set_metadata(self):
|
||||
sot = aggregate.Aggregate(**EXAMPLE)
|
||||
@ -95,6 +96,15 @@ class TestAggregate(base.TestCase):
|
||||
|
||||
url = 'os-aggregates/4/action'
|
||||
body = {"set_metadata": {"metadata": {"key: value"}}}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
url, json=body, microversion=None)
|
||||
|
||||
def test_precache_image(self):
|
||||
sot = aggregate.Aggregate(**EXAMPLE)
|
||||
|
||||
sot.precache_images(self.sess, ['1'])
|
||||
|
||||
url = 'os-aggregates/4/images'
|
||||
body = {"cache": ['1']}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, microversion=sot._max_microversion)
|
||||
|
@ -12,6 +12,7 @@
|
||||
from unittest import mock
|
||||
|
||||
from openstack.compute.v2 import _proxy
|
||||
from openstack.compute.v2 import aggregate
|
||||
from openstack.compute.v2 import availability_zone as az
|
||||
from openstack.compute.v2 import extension
|
||||
from openstack.compute.v2 import flavor
|
||||
@ -245,6 +246,63 @@ class TestKeyPair(TestComputeProxy):
|
||||
)
|
||||
|
||||
|
||||
class TestAggregate(TestComputeProxy):
|
||||
def test_aggregate_create(self):
|
||||
self.verify_create(self.proxy.create_aggregate, aggregate.Aggregate)
|
||||
|
||||
def test_aggregate_delete(self):
|
||||
self.verify_delete(
|
||||
self.proxy.delete_aggregate, aggregate.Aggregate, False)
|
||||
|
||||
def test_aggregate_delete_ignore(self):
|
||||
self.verify_delete(
|
||||
self.proxy.delete_aggregate, aggregate.Aggregate, True)
|
||||
|
||||
def test_aggregate_find(self):
|
||||
self.verify_find(self.proxy.find_aggregate, aggregate.Aggregate)
|
||||
|
||||
def test_aggregates(self):
|
||||
self.verify_list_no_kwargs(self.proxy.aggregates, aggregate.Aggregate)
|
||||
|
||||
def test_aggregate_get(self):
|
||||
self.verify_get(self.proxy.get_aggregate, aggregate.Aggregate)
|
||||
|
||||
def test_aggregate_update(self):
|
||||
self.verify_update(self.proxy.update_aggregate, aggregate.Aggregate)
|
||||
|
||||
def test_aggregate_add_host(self):
|
||||
self._verify("openstack.compute.v2.aggregate.Aggregate.add_host",
|
||||
self.proxy.add_host_to_aggregate,
|
||||
method_args=["value", "host"],
|
||||
expected_args=["host"])
|
||||
|
||||
def test_aggregate_remove_host(self):
|
||||
self._verify("openstack.compute.v2.aggregate.Aggregate.remove_host",
|
||||
self.proxy.remove_host_from_aggregate,
|
||||
method_args=["value", "host"],
|
||||
expected_args=["host"])
|
||||
|
||||
def test_aggregate_set_metadata(self):
|
||||
self._verify("openstack.compute.v2.aggregate.Aggregate.set_metadata",
|
||||
self.proxy.set_aggregate_metadata,
|
||||
method_args=["value", {'a': 'b'}],
|
||||
expected_args=[{'a': 'b'}])
|
||||
|
||||
def test_aggregate_precache_image(self):
|
||||
self._verify(
|
||||
"openstack.compute.v2.aggregate.Aggregate.precache_images",
|
||||
self.proxy.aggregate_precache_images,
|
||||
method_args=["value", '1'],
|
||||
expected_args=[[{'id': '1'}]])
|
||||
|
||||
def test_aggregate_precache_images(self):
|
||||
self._verify(
|
||||
"openstack.compute.v2.aggregate.Aggregate.precache_images",
|
||||
self.proxy.aggregate_precache_images,
|
||||
method_args=["value", ['1', '2']],
|
||||
expected_args=[[{'id': '1'}, {'id': '2'}]])
|
||||
|
||||
|
||||
class TestCompute(TestComputeProxy):
|
||||
def test_extension_find(self):
|
||||
self.verify_find(self.proxy.find_extension, extension.Extension)
|
||||
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
features:
|
||||
- Complete compute.aggregate functions to the latest state
|
||||
fixes:
|
||||
- aggregate.deleted property is renamed to 'is_deleted' to comply with the
|
||||
naming convention
|
Loading…
Reference in New Issue
Block a user