Merge "Add support for updating instance type"

This commit is contained in:
Jenkins 2017-01-03 16:02:18 +00:00 committed by Gerrit Code Review
commit 6065ebfa10
9 changed files with 143 additions and 11 deletions

View File

@ -94,6 +94,53 @@ Response
.. literalinclude:: ../../doc/api_samples/types/type-create-post-resp.json .. literalinclude:: ../../doc/api_samples/types/type-create-post-resp.json
:language: javascript :language: javascript
Update Type
===========
.. rest_method:: PUT /types/{type_uuid}
Updates a type.
Updating a type is typically only available to administrators of a
cloud because this has implications for scheduling efficiently in the cloud.
Normal response codes: 200
Error response codes: badRequest(400), unauthorized(401), forbidden(403),
conflict(409)
Request
-------
.. rest_parameters:: parameters.yaml
- name: type_name
- description: type_description
- is_public: type_is_public_not_required
**Example Update Type**
.. literalinclude:: ../../doc/api_samples/types/type-update-put-req.json
:language: javascript
Response
--------
.. rest_parameters:: parameters.yaml
- name: type_name
- links: links
- description: type_description
- uuid: type_uuid
- created_at: created_at
- updated_at: updated_at
- is_public: type_is_public
- extra_specs: type_extra_specs
**Example Update type**
.. literalinclude:: ../../doc/api_samples/types/type-update-put-resp.json
:language: javascript
Show Type Details Show Type Details
=================== ===================

View File

@ -0,0 +1,5 @@
{
"name": "updated_type",
"description": "this is a type to be updated",
"is_public": false
}

View File

@ -0,0 +1,19 @@
{
"description": "this is a type to be updated",
"links": [
{
"href": "http://10.3.150.17:6688/v1/types/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
"rel": "self"
},
{
"href": "http://10.3.150.17:6688/types/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
"rel": "bookmark"
}
],
"created_at": "2016-09-27T02:37:21.966342+00:00",
"uuid": "7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
"updated_at": null,
"extra_specs": {},
"is_public": false,
"name": "updated_type"
}

View File

@ -23,6 +23,8 @@ from nimble.api.controllers import base
from nimble.api.controllers import link from nimble.api.controllers import link
from nimble.api.controllers.v1 import types from nimble.api.controllers.v1 import types
from nimble.api import expose from nimble.api import expose
from nimble.common import exception
from nimble.common.i18n import _
from nimble import objects from nimble import objects
@ -161,6 +163,34 @@ class InstanceTypeController(rest.RestController):
new_instance_type.uuid) new_instance_type.uuid)
return InstanceType.convert_with_links(new_instance_type) return InstanceType.convert_with_links(new_instance_type)
@expose.expose(InstanceType, types.uuid, body=InstanceType)
def put(self, instance_type_uuid, instance_type):
"""Update an instance type.
:param instance_type_uuid: the uuid of instance_type to be updated.
:param instance_type: a instance type within the request body.
"""
try:
inst_type_in_db = objects.InstanceType.get(
pecan.request.context, instance_type_uuid)
except exception.InstanceTypeNotFound:
msg = (_("InstanceType %s could not be found") %
instance_type_uuid)
raise wsme.exc.ClientSideError(
msg, status_code=http_client.BAD_REQUEST)
need_to_update = False
for attr in ('name', 'description', 'is_public'):
if getattr(instance_type, attr) != wtypes.Unset:
need_to_update = True
setattr(inst_type_in_db, attr, getattr(instance_type, attr))
# don't need to call db_api if no update
if need_to_update:
inst_type_in_db.save()
# Set the HTTP Location Header
pecan.response.location = link.build_url('instance_type',
inst_type_in_db.uuid)
return InstanceType.convert_with_links(inst_type_in_db)
@expose.expose(None, types.uuid, status_code=http_client.NO_CONTENT) @expose.expose(None, types.uuid, status_code=http_client.NO_CONTENT)
def delete(self, instance_type_uuid): def delete(self, instance_type_uuid):
"""Delete an instance type. """Delete an instance type.

View File

@ -50,6 +50,9 @@ class Connection(object):
def instance_type_get(self, context, instance_type_uuid): def instance_type_get(self, context, instance_type_uuid):
"""Get instance type by uuid.""" """Get instance type by uuid."""
def instance_type_update(self, context, instance_type_id, values):
"""Update an instance type."""
@abc.abstractmethod @abc.abstractmethod
def instance_type_get_all(self, context): def instance_type_get_all(self, context):
"""Get all instance types.""" """Get all instance types."""

View File

@ -137,6 +137,19 @@ class Connection(api.Connection):
raise exception.InstanceTypeNotFound( raise exception.InstanceTypeNotFound(
instance_type=instance_type_uuid) instance_type=instance_type_uuid)
def instance_type_update(self, context, instance_type_id, values):
with _session_for_write():
query = model_query(context, models.InstanceTypes)
query = add_identity_filter(query, instance_type_id)
try:
ref = query.with_lockmode('update').one()
except NoResultFound:
raise exception.InstanceTypeNotFound(
instance_type=instance_type_id)
ref.update(values)
return ref
def instance_type_get_all(self, context): def instance_type_get_all(self, context):
results = model_query(context, models.InstanceTypes) results = model_query(context, models.InstanceTypes)
return [_dict_with_extra_specs(i) for i in results] return [_dict_with_extra_specs(i) for i in results]

View File

@ -16,7 +16,6 @@
from oslo_versionedobjects import base as object_base from oslo_versionedobjects import base as object_base
from nimble.common import exception
from nimble.db import api as dbapi from nimble.db import api as dbapi
from nimble.objects import base from nimble.objects import base
from nimble.objects import fields as object_fields from nimble.objects import fields as object_fields
@ -92,10 +91,6 @@ class InstanceType(base.NimbleObject, object_base.VersionedObjectDictCompat):
def save(self, context=None): def save(self, context=None):
updates = self.obj_get_changes() updates = self.obj_get_changes()
extra_specs = updates.pop('extra_specs', None) extra_specs = updates.pop('extra_specs', None)
if updates:
raise exception.ObjectActionError(
action='save', reason='read-only fields were changed')
if extra_specs is not None: if extra_specs is not None:
deleted_keys = (set(self._orig_extra_specs.keys()) - deleted_keys = (set(self._orig_extra_specs.keys()) -
set(extra_specs.keys())) set(extra_specs.keys()))
@ -105,6 +100,7 @@ class InstanceType(base.NimbleObject, object_base.VersionedObjectDictCompat):
if added_keys or deleted_keys: if added_keys or deleted_keys:
self.save_extra_specs(context, self.extra_specs, deleted_keys) self.save_extra_specs(context, self.extra_specs, deleted_keys)
self.dbapi.instance_type_update(context, self.uuid, updates)
def save_extra_specs(self, context, to_add=None, to_delete=None): def save_extra_specs(self, context, to_add=None, to_delete=None):
"""Add or delete extra_specs. """Add or delete extra_specs.

View File

@ -69,6 +69,19 @@ class TestInstanceType(v1_test.APITestV1):
resp = self.get_json('/types') resp = self.get_json('/types')
self.assertEqual(3, len(resp['types'])) self.assertEqual(3, len(resp['types']))
def test_instance_type_update(self):
self._prepare_instance_types()
resp = self.get_json('/types/' + self.TYPE_UUIDS[0])
self.assertEqual('test0', resp['name'])
self.assertEqual('just test0', resp['description'])
values = {"name": "update_name", "description": "updated_description",
"is_public": False}
self.put_json('/types/' + self.TYPE_UUIDS[0], values, status=200)
resp = self.get_json('/types/' + self.TYPE_UUIDS[0])
self.assertEqual('update_name', resp['name'])
self.assertEqual('updated_description', resp['description'])
self.assertEqual(False, resp['is_public'])
class TestInstanceTypeExtra(v1_test.APITestV1): class TestInstanceTypeExtra(v1_test.APITestV1):
TYPE_UUID = 'ff28b5a2-73e5-431c-b4b7-1b96b74bca7b' TYPE_UUID = 'ff28b5a2-73e5-431c-b4b7-1b96b74bca7b'

View File

@ -14,7 +14,6 @@
import mock import mock
from oslo_context import context from oslo_context import context
from nimble.common import exception
from nimble import objects from nimble import objects
from nimble.tests.unit.db import base from nimble.tests.unit.db import base
from nimble.tests.unit.db import utils from nimble.tests.unit.db import utils
@ -72,8 +71,15 @@ class TestInstanceTypeObject(base.DbTestCase):
mock_type_destroy.assert_called_once_with(self.context, uuid) mock_type_destroy.assert_called_once_with(self.context, uuid)
def test_save(self): def test_save(self):
uuid = self.fake_type['uuid']
with mock.patch.object(self.dbapi, 'instance_type_update',
autospec=True) as mock_inst_type_update:
instance_type = objects.InstanceType(self.context, instance_type = objects.InstanceType(self.context,
**self.fake_type) **self.fake_type)
self.assertRaises(exception.ObjectActionError, instance_type.name = 'changed_name'
instance_type.save, updates = instance_type.obj_get_changes()
self.context) instance_type.save(self.context)
updates.pop('extra_specs', None)
mock_inst_type_update.return_value = self.fake_type
mock_inst_type_update.assert_called_once_with(
self.context, uuid, updates)