nova/nova/tests/unit/api/openstack/compute/test_server_tags.py

360 lines
16 KiB
Python

# 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.
import mock
from webob import exc
from nova.api.openstack.compute import server_tags
from nova.api.openstack.compute import servers
from nova.compute import vm_states
from nova import context
from nova.db.main import models
from nova import exception
from nova import objects
from nova.objects import instance
from nova.objects import tag as tag_obj
from nova import test
from nova.tests.unit.api.openstack import fakes
from nova.tests.unit import fake_instance
UUID = 'b48316c5-71e8-45e4-9884-6c78055b9b13'
TAG1 = 'tag1'
TAG2 = 'tag2'
TAG3 = 'tag3'
TAGS = [TAG1, TAG2, TAG3]
NON_EXISTING_UUID = '123'
def return_server(compute_api, context, instance_id, expected_attrs=None):
return fake_instance.fake_instance_obj(context, vm_state=vm_states.ACTIVE)
def return_invalid_server(compute_api, context, instance_id,
expected_attrs=None):
return fake_instance.fake_instance_obj(context,
vm_state=vm_states.BUILDING)
class ServerTagsTest(test.TestCase):
api_version = '2.26'
def setUp(self):
super(ServerTagsTest, self).setUp()
self.controller = server_tags.ServerTagsController()
inst_map = objects.InstanceMapping(
project_id=fakes.FAKE_PROJECT_ID,
cell_mapping=objects.CellMappingList.get_all(
context.get_admin_context())[1])
self.stub_out('nova.objects.InstanceMapping.get_by_instance_uuid',
lambda s, c, u: inst_map)
def _get_tag(self, tag_name):
tag = models.Tag()
tag.tag = tag_name
tag.resource_id = UUID
return tag
def _get_request(self, url, method):
request = fakes.HTTPRequest.blank(url, version=self.api_version)
request.method = method
return request
@mock.patch('nova.db.main.api.instance_tag_exists')
def test_show(self, mock_exists):
mock_exists.return_value = True
req = self._get_request(
'/v2/%s/servers/%s/tags/%s' % (
fakes.FAKE_PROJECT_ID, UUID, TAG1), 'GET')
self.controller.show(req, UUID, TAG1)
mock_exists.assert_called_once_with(mock.ANY, UUID, TAG1)
@mock.patch('nova.db.main.api.instance_tag_get_by_instance_uuid')
def test_index(self, mock_db_get_inst_tags):
fake_tags = [self._get_tag(tag) for tag in TAGS]
mock_db_get_inst_tags.return_value = fake_tags
req = self._get_request('/v2/%s/servers/%s/tags' % (
fakes.FAKE_PROJECT_ID, UUID), 'GET')
res = self.controller.index(req, UUID)
self.assertEqual(TAGS, res.get('tags'))
mock_db_get_inst_tags.assert_called_once_with(mock.ANY, UUID)
@mock.patch('nova.notifications.base.send_instance_update_notification')
@mock.patch('nova.db.main.api.instance_tag_set')
def test_update_all(self, mock_db_set_inst_tags, mock_notify):
self.stub_out('nova.api.openstack.common.get_instance', return_server)
fake_tags = [self._get_tag(tag) for tag in TAGS]
mock_db_set_inst_tags.return_value = fake_tags
req = self._get_request(
'/v2/%s/servers/%s/tags' % (fakes.FAKE_PROJECT_ID, UUID), 'PUT')
res = self.controller.update_all(req, UUID, body={'tags': TAGS})
self.assertEqual(TAGS, res['tags'])
mock_db_set_inst_tags.assert_called_once_with(mock.ANY, UUID, TAGS)
self.assertEqual(1, mock_notify.call_count)
def test_update_all_too_many_tags(self):
self.stub_out('nova.api.openstack.common.get_instance', return_server)
fake_tags = {'tags': [str(i) for i in range(
instance.MAX_TAG_COUNT + 1)]}
req = self._get_request(
'/v2/%s/servers/%s/tags' % (fakes.FAKE_PROJECT_ID, UUID), 'PUT')
self.assertRaises(exception.ValidationError,
self.controller.update_all,
req, UUID, body=fake_tags)
def test_update_all_forbidden_characters(self):
self.stub_out('nova.api.openstack.common.get_instance', return_server)
req = self._get_request('/v2/%s/servers/%s/tags' % (
fakes.FAKE_PROJECT_ID, UUID), 'PUT')
for tag in ['tag,1', 'tag/1']:
self.assertRaises(exception.ValidationError,
self.controller.update_all,
req, UUID, body={'tags': [tag, 'tag2']})
def test_update_all_invalid_tag_type(self):
req = self._get_request('/v2/%s/servers/%s/tags' % (
fakes.FAKE_PROJECT_ID, UUID), 'PUT')
self.assertRaises(exception.ValidationError,
self.controller.update_all,
req, UUID, body={'tags': [1]})
def test_update_all_tags_with_one_tag_empty_string(self):
req = self._get_request('/v2/%s/servers/%s/tags' % (
fakes.FAKE_PROJECT_ID, UUID), 'PUT')
self.assertRaises(exception.ValidationError,
self.controller.update_all,
req, UUID, body={'tags': ['tag1', '']})
def test_update_all_too_long_tag(self):
self.stub_out('nova.api.openstack.common.get_instance', return_server)
req = self._get_request('/v2/%s/servers/%s/tags' % (
fakes.FAKE_PROJECT_ID, UUID), 'PUT')
tag = "a" * (tag_obj.MAX_TAG_LENGTH + 1)
self.assertRaises(exception.ValidationError,
self.controller.update_all,
req, UUID, body={'tags': [tag]})
def test_update_all_invalid_tag_list_type(self):
req = self._get_request('/v2/%s/servers/%s/tags' % (
fakes.FAKE_PROJECT_ID, UUID), 'PUT')
self.assertRaises(exception.ValidationError,
self.controller.update_all,
req, UUID, body={'tags': {'tag': 'tag'}})
def test_update_all_invalid_instance_state(self):
self.stub_out('nova.api.openstack.common.get_instance',
return_invalid_server)
req = self._get_request('/v2/%s/servers/%s/tags' % (
fakes.FAKE_PROJECT_ID, UUID), 'PUT')
self.assertRaises(exc.HTTPConflict, self.controller.update_all,
req, UUID, body={'tags': TAGS})
@mock.patch('nova.db.main.api.instance_tag_exists')
def test_show_non_existing_tag(self, mock_exists):
mock_exists.return_value = False
req = self._get_request(
'/v2/%s/servers/%s/tags/%s' % (
fakes.FAKE_PROJECT_ID, UUID, TAG1), 'GET')
self.assertRaises(exc.HTTPNotFound, self.controller.show,
req, UUID, TAG1)
@mock.patch('nova.notifications.base.send_instance_update_notification')
@mock.patch('nova.db.main.api.instance_tag_add')
@mock.patch('nova.db.main.api.instance_tag_get_by_instance_uuid')
def test_update(self, mock_db_get_inst_tags, mock_db_add_inst_tags,
mock_notify):
self.stub_out('nova.api.openstack.common.get_instance', return_server)
mock_db_get_inst_tags.return_value = [self._get_tag(TAG1)]
mock_db_add_inst_tags.return_value = self._get_tag(TAG2)
url = '/v2/%s/servers/%s/tags/%s' % (fakes.FAKE_PROJECT_ID, UUID, TAG2)
location = 'http://localhost' + url
req = self._get_request(url, 'PUT')
res = self.controller.update(req, UUID, TAG2, body=None)
self.assertEqual(201, res.status_int)
self.assertEqual(0, len(res.body))
self.assertEqual(location, res.headers['Location'])
mock_db_add_inst_tags.assert_called_once_with(mock.ANY, UUID, TAG2)
self.assertEqual(2, mock_db_get_inst_tags.call_count)
self.assertEqual(1, mock_notify.call_count)
@mock.patch('nova.db.main.api.instance_tag_get_by_instance_uuid')
def test_update_existing_tag(self, mock_db_get_inst_tags):
self.stub_out('nova.api.openstack.common.get_instance', return_server)
mock_db_get_inst_tags.return_value = [self._get_tag(TAG1)]
req = self._get_request(
'/v2/%s/servers/%s/tags/%s' % (
fakes.FAKE_PROJECT_ID, UUID, TAG1), 'PUT')
res = self.controller.update(req, UUID, TAG1, body=None)
self.assertEqual(204, res.status_int)
self.assertEqual(0, len(res.body))
mock_db_get_inst_tags.assert_called_once_with(mock.ANY, UUID)
@mock.patch('nova.db.main.api.instance_tag_get_by_instance_uuid')
def test_update_tag_limit_exceed(self, mock_db_get_inst_tags):
self.stub_out('nova.api.openstack.common.get_instance', return_server)
fake_tags = [self._get_tag(str(i))
for i in range(instance.MAX_TAG_COUNT)]
mock_db_get_inst_tags.return_value = fake_tags
req = self._get_request(
'/v2/%s/servers/%s/tags/%s' % (
fakes.FAKE_PROJECT_ID, UUID, TAG2), 'PUT')
self.assertRaises(exc.HTTPBadRequest, self.controller.update,
req, UUID, TAG2, body=None)
@mock.patch('nova.db.main.api.instance_tag_get_by_instance_uuid')
def test_update_too_long_tag(self, mock_db_get_inst_tags):
self.stub_out('nova.api.openstack.common.get_instance', return_server)
mock_db_get_inst_tags.return_value = []
tag = "a" * (tag_obj.MAX_TAG_LENGTH + 1)
req = self._get_request(
'/v2/%s/servers/%s/tags/%s' % (
fakes.FAKE_PROJECT_ID, UUID, tag), 'PUT')
self.assertRaises(exc.HTTPBadRequest, self.controller.update,
req, UUID, tag, body=None)
@mock.patch('nova.db.main.api.instance_tag_get_by_instance_uuid')
def test_update_forbidden_characters(self, mock_db_get_inst_tags):
self.stub_out('nova.api.openstack.common.get_instance', return_server)
mock_db_get_inst_tags.return_value = []
for tag in ['tag,1', 'tag/1']:
req = self._get_request(
'/v2/%s/servers/%s/tags/%s' % (
fakes.FAKE_PROJECT_ID, UUID, tag), 'PUT')
self.assertRaises(exc.HTTPBadRequest, self.controller.update,
req, UUID, tag, body=None)
def test_update_invalid_instance_state(self):
self.stub_out('nova.api.openstack.common.get_instance',
return_invalid_server)
req = self._get_request(
'/v2/%s/servers/%s/tags/%s' % (
fakes.FAKE_PROJECT_ID, UUID, TAG1), 'PUT')
self.assertRaises(exc.HTTPConflict, self.controller.update, req, UUID,
TAG1, body=None)
@mock.patch('nova.db.main.api.instance_tag_get_by_instance_uuid')
@mock.patch('nova.notifications.base.send_instance_update_notification')
@mock.patch('nova.db.main.api.instance_tag_delete')
def test_delete(self, mock_db_delete_inst_tags, mock_notify,
mock_db_get_inst_tags):
self.stub_out('nova.api.openstack.common.get_instance', return_server)
req = self._get_request(
'/v2/%s/servers/%s/tags/%s' % (
fakes.FAKE_PROJECT_ID, UUID, TAG2), 'DELETE')
self.controller.delete(req, UUID, TAG2)
mock_db_delete_inst_tags.assert_called_once_with(mock.ANY, UUID, TAG2)
mock_db_get_inst_tags.assert_called_once_with(mock.ANY, UUID)
self.assertEqual(1, mock_notify.call_count)
@mock.patch('nova.db.main.api.instance_tag_delete')
def test_delete_non_existing_tag(self, mock_db_delete_inst_tags):
self.stub_out('nova.api.openstack.common.get_instance', return_server)
def fake_db_delete_tag(context, instance_uuid, tag):
self.assertEqual(UUID, instance_uuid)
self.assertEqual(TAG1, tag)
raise exception.InstanceTagNotFound(instance_id=instance_uuid,
tag=tag)
mock_db_delete_inst_tags.side_effect = fake_db_delete_tag
req = self._get_request(
'/v2/%s/servers/%s/tags/%s' % (
fakes.FAKE_PROJECT_ID, UUID, TAG1), 'DELETE')
self.assertRaises(exc.HTTPNotFound, self.controller.delete,
req, UUID, TAG1)
def test_delete_invalid_instance_state(self):
self.stub_out('nova.api.openstack.common.get_instance',
return_invalid_server)
req = self._get_request(
'/v2/%s/servers/%s/tags/%s' % (
fakes.FAKE_PROJECT_ID, UUID, TAG2), 'DELETE')
self.assertRaises(exc.HTTPConflict, self.controller.delete, req, UUID,
TAG1)
@mock.patch('nova.notifications.base.send_instance_update_notification')
@mock.patch('nova.db.main.api.instance_tag_delete_all')
def test_delete_all(self, mock_db_delete_inst_tags, mock_notify):
self.stub_out('nova.api.openstack.common.get_instance', return_server)
req = self._get_request('/v2/%s/servers/%s/tags' % (
fakes.FAKE_PROJECT_ID, UUID), 'DELETE')
self.controller.delete_all(req, UUID)
mock_db_delete_inst_tags.assert_called_once_with(mock.ANY, UUID)
self.assertEqual(1, mock_notify.call_count)
def test_delete_all_invalid_instance_state(self):
self.stub_out('nova.api.openstack.common.get_instance',
return_invalid_server)
req = self._get_request('/v2/%s/servers/%s/tags' % (
fakes.FAKE_PROJECT_ID, UUID), 'DELETE')
self.assertRaises(exc.HTTPConflict, self.controller.delete_all, req,
UUID)
def test_show_non_existing_instance(self):
req = self._get_request(
'/v2/%s/servers/%s/tags/%s' % (
fakes.FAKE_PROJECT_ID, NON_EXISTING_UUID, TAG1), 'GET')
self.assertRaises(exc.HTTPNotFound, self.controller.show, req,
NON_EXISTING_UUID, TAG1)
def test_show_with_details_information_non_existing_instance(self):
req = self._get_request(
'/v2/%s/servers/%s' % (
fakes.FAKE_PROJECT_ID, NON_EXISTING_UUID), 'GET')
servers_controller = servers.ServersController()
self.assertRaises(exc.HTTPNotFound, servers_controller.show, req,
NON_EXISTING_UUID)
def test_index_non_existing_instance(self):
req = self._get_request(
'v2/%s/servers/%s/tags' % (
fakes.FAKE_PROJECT_ID, NON_EXISTING_UUID), 'GET')
self.assertRaises(exc.HTTPNotFound, self.controller.index, req,
NON_EXISTING_UUID)
def test_update_non_existing_instance(self):
req = self._get_request(
'/v2/%s/servers/%s/tags/%s' % (
fakes.FAKE_PROJECT_ID, NON_EXISTING_UUID, TAG1), 'PUT')
self.assertRaises(exc.HTTPNotFound, self.controller.update, req,
NON_EXISTING_UUID, TAG1, body=None)
def test_update_all_non_existing_instance(self):
req = self._get_request(
'/v2/%s/servers/%s/tags' % (
fakes.FAKE_PROJECT_ID, NON_EXISTING_UUID), 'PUT')
self.assertRaises(exc.HTTPNotFound, self.controller.update_all, req,
NON_EXISTING_UUID, body={'tags': TAGS})
def test_delete_non_existing_instance(self):
req = self._get_request(
'/v2/%s/servers/%s/tags/%s' % (
fakes.FAKE_PROJECT_ID, NON_EXISTING_UUID, TAG1), 'DELETE')
self.assertRaises(exc.HTTPNotFound, self.controller.delete, req,
NON_EXISTING_UUID, TAG1)
def test_delete_all_non_existing_instance(self):
req = self._get_request(
'/v2/%s/servers/%s/tags' % (
fakes.FAKE_PROJECT_ID, NON_EXISTING_UUID), 'DELETE')
self.assertRaises(exc.HTTPNotFound, self.controller.delete_all,
req, NON_EXISTING_UUID)