78b68ba0da
We have PERSONALITY property on OS::Nova::Server that defaults to {}, but code that triggers check for limits compares value of property to None -> this property always get validated for limits (if limit is set). Change-Id: I552a03cd9f4ab570aa059349ab361bb50c9c0d1e Closes-bug: #1333283
2567 lines
107 KiB
Python
2567 lines
107 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 collections
|
|
import copy
|
|
import six
|
|
import uuid
|
|
|
|
import mock
|
|
import mox
|
|
from novaclient import exceptions as nova_exceptions
|
|
|
|
from heat.common import exception
|
|
from heat.common import template_format
|
|
from heat.engine.clients.os import glance
|
|
from heat.engine.clients.os import nova
|
|
from heat.engine import environment
|
|
from heat.engine import parser
|
|
from heat.engine import resource
|
|
from heat.engine.resources import nova_utils
|
|
from heat.engine.resources import server as servers
|
|
from heat.engine.resources.software_config import software_config as sc
|
|
from heat.engine import scheduler
|
|
from heat.openstack.common.gettextutils import _
|
|
from heat.tests.common import HeatTestCase
|
|
from heat.tests import fakes
|
|
from heat.tests import utils
|
|
from heat.tests.v1_1 import fakes as fakes_v1_1
|
|
|
|
|
|
wp_template = '''
|
|
{
|
|
"AWSTemplateFormatVersion" : "2010-09-09",
|
|
"Description" : "WordPress",
|
|
"Parameters" : {
|
|
"key_name" : {
|
|
"Description" : "key_name",
|
|
"Type" : "String",
|
|
"Default" : "test"
|
|
}
|
|
},
|
|
"Resources" : {
|
|
"WebServer": {
|
|
"Type": "OS::Nova::Server",
|
|
"Properties": {
|
|
"image" : "F17-x86_64-gold",
|
|
"flavor" : "m1.large",
|
|
"key_name" : "test",
|
|
"user_data" : "wordpress"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
'''
|
|
|
|
|
|
class ServersTest(HeatTestCase):
|
|
def setUp(self):
|
|
super(ServersTest, self).setUp()
|
|
self.fc = fakes_v1_1.FakeClient()
|
|
self.stub_keystoneclient()
|
|
self.limits = self.m.CreateMockAnything()
|
|
self.limits.absolute = self._limits_absolute()
|
|
|
|
def _limits_absolute(self):
|
|
max_personality = self.m.CreateMockAnything()
|
|
max_personality.name = 'maxPersonality'
|
|
max_personality.value = 5
|
|
max_personality_size = self.m.CreateMockAnything()
|
|
max_personality_size.name = 'maxPersonalitySize'
|
|
max_personality_size.value = 10240
|
|
max_server_meta = self.m.CreateMockAnything()
|
|
max_server_meta.name = 'maxServerMeta'
|
|
max_server_meta.value = 3
|
|
yield max_personality
|
|
yield max_personality_size
|
|
yield max_server_meta
|
|
|
|
def _setup_test_stack(self, stack_name):
|
|
t = template_format.parse(wp_template)
|
|
template = parser.Template(t)
|
|
stack = parser.Stack(utils.dummy_context(), stack_name, template,
|
|
environment.Environment({'key_name': 'test'}),
|
|
stack_id=str(uuid.uuid4()),
|
|
stack_user_project_id='8888')
|
|
return (template, stack)
|
|
|
|
def _get_test_template(self, stack_name, server_name=None,
|
|
image_id=None):
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
tmpl.t['Resources']['WebServer']['Properties']['image'] = \
|
|
image_id or 'CentOS 5.2'
|
|
tmpl.t['Resources']['WebServer']['Properties']['flavor'] = \
|
|
'256 MB Server'
|
|
|
|
if server_name is not None:
|
|
tmpl.t['Resources']['WebServer']['Properties']['name'] = \
|
|
server_name
|
|
|
|
return tmpl, stack
|
|
|
|
def _setup_test_server(self, return_server, name, image_id=None,
|
|
override_name=False, stub_create=True,
|
|
server_rebuild=False):
|
|
stack_name = '%s_s' % name
|
|
server_name = str(name) if override_name else None
|
|
tmpl, stack = self._get_test_template(stack_name, server_name,
|
|
image_id)
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server(str(name), resource_defns['WebServer'],
|
|
stack)
|
|
|
|
self._mock_get_image_id_success(image_id or 'CentOS 5.2', 1,
|
|
server_rebuild=server_rebuild)
|
|
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
|
|
if stub_create:
|
|
self.m.StubOutWithMock(self.fc.servers, 'create')
|
|
self.fc.servers.create(
|
|
image=1, flavor=1, key_name='test',
|
|
name=override_name and server.name or utils.PhysName(
|
|
stack_name, server.name),
|
|
security_groups=[],
|
|
userdata=mox.IgnoreArg(), scheduler_hints=None,
|
|
meta=None, nics=None, availability_zone=None,
|
|
block_device_mapping=None, config_drive=None,
|
|
disk_config=None, reservation_id=None, files={},
|
|
admin_pass=None).AndReturn(return_server)
|
|
|
|
return server
|
|
|
|
def _create_test_server(self, return_server, name, override_name=False,
|
|
stub_create=True, server_rebuild=False):
|
|
server = self._setup_test_server(return_server, name,
|
|
stub_create=stub_create,
|
|
server_rebuild=server_rebuild)
|
|
self.m.ReplayAll()
|
|
scheduler.TaskRunner(server.create)()
|
|
return server
|
|
|
|
def _create_fake_iface(self, port, mac, ip):
|
|
class fake_interface():
|
|
def __init__(self, port_id, mac_addr, fixed_ip):
|
|
self.port_id = port_id
|
|
self.mac_addr = mac_addr
|
|
self.fixed_ips = [{'ip_address': fixed_ip}]
|
|
|
|
return fake_interface(port, mac, ip)
|
|
|
|
def _mock_get_image_id_success(self, imageId_input, imageId,
|
|
server_rebuild=False):
|
|
self.m.StubOutWithMock(glance.GlanceClientPlugin, 'get_image_id')
|
|
glance.GlanceClientPlugin.get_image_id(
|
|
imageId_input).MultipleTimes().AndReturn(imageId)
|
|
|
|
if server_rebuild:
|
|
glance.GlanceClientPlugin.get_image_id('F17-x86_64-gold').\
|
|
MultipleTimes().AndReturn(744)
|
|
|
|
def _mock_get_image_id_fail(self, image_id, exp):
|
|
self.m.StubOutWithMock(glance.GlanceClientPlugin, 'get_image_id')
|
|
glance.GlanceClientPlugin.get_image_id(image_id).AndRaise(exp)
|
|
|
|
def _mock_get_keypair_success(self, keypair_input, keypair):
|
|
n_cli_mock = self.m.CreateMockAnything()
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(
|
|
n_cli_mock)
|
|
self.m.StubOutWithMock(nova_utils, 'get_keypair')
|
|
nova_utils.get_keypair(n_cli_mock, keypair_input).MultipleTimes().\
|
|
AndReturn(keypair)
|
|
|
|
def _server_validate_mock(self, server):
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', 'image_id')
|
|
|
|
def test_server_create(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
return_server.id = '5678'
|
|
server_name = 'test_server_create'
|
|
stack_name = '%s_s' % server_name
|
|
server = self._create_test_server(return_server, server_name)
|
|
|
|
# this makes sure the auto increment worked on server creation
|
|
self.assertTrue(server.id > 0)
|
|
|
|
interfaces = [
|
|
self._create_fake_iface('1234', 'fa:16:3e:8c:22:aa', '4.5.6.7'),
|
|
self._create_fake_iface('5678', 'fa:16:3e:8c:33:bb', '5.6.9.8'),
|
|
self._create_fake_iface(
|
|
'1013', 'fa:16:3e:8c:44:cc', '10.13.12.13')]
|
|
|
|
self.m.StubOutWithMock(self.fc.servers, 'get')
|
|
self.fc.servers.get('5678').MultipleTimes().AndReturn(return_server)
|
|
|
|
self.m.StubOutWithMock(return_server, 'interface_list')
|
|
return_server.interface_list().MultipleTimes().AndReturn(interfaces)
|
|
self.m.ReplayAll()
|
|
|
|
public_ip = return_server.networks['public'][0]
|
|
self.assertEqual('1234',
|
|
server.FnGetAtt('addresses')['public'][0]['port'])
|
|
self.assertEqual('5678',
|
|
server.FnGetAtt('addresses')['public'][1]['port'])
|
|
self.assertEqual(public_ip,
|
|
server.FnGetAtt('addresses')['public'][0]['addr'])
|
|
self.assertEqual(public_ip,
|
|
server.FnGetAtt('networks')['public'][0])
|
|
|
|
private_ip = return_server.networks['private'][0]
|
|
self.assertEqual('1013',
|
|
server.FnGetAtt('addresses')['private'][0]['port'])
|
|
self.assertEqual(private_ip,
|
|
server.FnGetAtt('addresses')['private'][0]['addr'])
|
|
self.assertEqual(private_ip,
|
|
server.FnGetAtt('networks')['private'][0])
|
|
self.assertIn(
|
|
server.FnGetAtt('first_address'), (private_ip, public_ip))
|
|
|
|
self.assertEqual(return_server._info, server.FnGetAtt('show'))
|
|
self.assertEqual('sample-server2', server.FnGetAtt('instance_name'))
|
|
self.assertEqual('192.0.2.0', server.FnGetAtt('accessIPv4'))
|
|
self.assertEqual('::babe:4317:0A83', server.FnGetAtt('accessIPv6'))
|
|
|
|
expected_name = utils.PhysName(stack_name, server.name)
|
|
self.assertEqual(expected_name, server.FnGetAtt('name'))
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_create_metadata(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
stack_name = 'create_metadata_test_stack'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
tmpl['Resources']['WebServer']['Properties']['metadata'] = \
|
|
{'a': 1}
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('create_metadata_test_server',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
instance_meta = {'a': "1"}
|
|
image_id = mox.IgnoreArg()
|
|
self.m.StubOutWithMock(self.fc.servers, 'create')
|
|
self.fc.servers.create(
|
|
image=image_id, flavor=mox.IgnoreArg(), key_name='test',
|
|
name=mox.IgnoreArg(), security_groups=[],
|
|
userdata=mox.IgnoreArg(), scheduler_hints=None,
|
|
meta=instance_meta, nics=None, availability_zone=None,
|
|
block_device_mapping=None, config_drive=None,
|
|
disk_config=None, reservation_id=None, files={},
|
|
admin_pass=None).AndReturn(return_server)
|
|
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', image_id)
|
|
self.m.ReplayAll()
|
|
|
|
scheduler.TaskRunner(server.create)()
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_create_with_image_id(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
return_server.id = '5678'
|
|
server_name = 'test_server_create_image_id'
|
|
server = self._setup_test_server(return_server,
|
|
server_name,
|
|
image_id='1',
|
|
override_name=True)
|
|
|
|
interfaces = [
|
|
self._create_fake_iface('1234', 'fa:16:3e:8c:22:aa', '4.5.6.7'),
|
|
self._create_fake_iface('5678', 'fa:16:3e:8c:33:bb', '5.6.9.8'),
|
|
self._create_fake_iface(
|
|
'1013', 'fa:16:3e:8c:44:cc', '10.13.12.13')]
|
|
|
|
self.m.StubOutWithMock(self.fc.servers, 'get')
|
|
self.fc.servers.get('5678').MultipleTimes().AndReturn(return_server)
|
|
|
|
self.m.StubOutWithMock(return_server, 'interface_list')
|
|
return_server.interface_list().MultipleTimes().AndReturn(interfaces)
|
|
self.m.ReplayAll()
|
|
scheduler.TaskRunner(server.create)()
|
|
|
|
# this makes sure the auto increment worked on server creation
|
|
self.assertTrue(server.id > 0)
|
|
|
|
public_ip = return_server.networks['public'][0]
|
|
self.assertEqual('1234',
|
|
server.FnGetAtt('addresses')['public'][0]['port'])
|
|
self.assertEqual('5678',
|
|
server.FnGetAtt('addresses')['public'][1]['port'])
|
|
self.assertEqual(
|
|
server.FnGetAtt('addresses')['public'][0]['addr'], public_ip)
|
|
self.assertEqual(
|
|
server.FnGetAtt('networks')['public'][0], public_ip)
|
|
|
|
private_ip = return_server.networks['private'][0]
|
|
self.assertEqual('1013',
|
|
server.FnGetAtt('addresses')['private'][0]['port'])
|
|
self.assertEqual(
|
|
server.FnGetAtt('addresses')['private'][0]['addr'], private_ip)
|
|
self.assertEqual(
|
|
server.FnGetAtt('networks')['private'][0], private_ip)
|
|
self.assertIn(
|
|
server.FnGetAtt('first_address'), (private_ip, public_ip))
|
|
|
|
self.assertEqual(server_name, server.FnGetAtt('name'))
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_create_image_name_err(self):
|
|
stack_name = 'img_name_err'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
# create an server with non exist image name
|
|
tmpl['Resources']['WebServer']['Properties']['image'] = 'Slackware'
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('WebServer',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
self._mock_get_image_id_fail('Slackware',
|
|
exception.ImageNotFound(
|
|
image_name='Slackware'))
|
|
self._mock_get_keypair_success('test', ('test', 'abc123'))
|
|
self.m.ReplayAll()
|
|
|
|
create = scheduler.TaskRunner(server.create)
|
|
error = self.assertRaises(exception.ResourceFailure, create)
|
|
self.assertEqual(
|
|
'StackValidationFailed: Property error : WebServer: '
|
|
'image Error validating value \'Slackware\': '
|
|
'The Image (Slackware) could not be found.',
|
|
six.text_type(error))
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_create_duplicate_image_name_err(self):
|
|
stack_name = 'img_dup_err'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
# create an server with a non unique image name
|
|
tmpl['Resources']['WebServer']['Properties']['image'] = 'CentOS 5.2'
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('WebServer',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
self._mock_get_image_id_fail('CentOS 5.2',
|
|
exception.PhysicalResourceNameAmbiguity(
|
|
name='CentOS 5.2'))
|
|
self._mock_get_keypair_success('test', ('test', 'abc123'))
|
|
self.m.ReplayAll()
|
|
|
|
create = scheduler.TaskRunner(server.create)
|
|
error = self.assertRaises(exception.ResourceFailure, create)
|
|
self.assertEqual(
|
|
'StackValidationFailed: Property error : WebServer: '
|
|
'image Multiple physical resources were '
|
|
'found with name (CentOS 5.2).',
|
|
six.text_type(error))
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_create_image_id_err(self):
|
|
stack_name = 'img_id_err'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
# create an server with non exist image Id
|
|
tmpl['Resources']['WebServer']['Properties']['image'] = '1'
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('WebServer',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
self._mock_get_image_id_fail('1',
|
|
exception.ImageNotFound(image_name='1'))
|
|
self._mock_get_keypair_success('test', ('test', 'abc123'))
|
|
self.m.ReplayAll()
|
|
|
|
create = scheduler.TaskRunner(server.create)
|
|
error = self.assertRaises(exception.ResourceFailure, create)
|
|
self.assertEqual(
|
|
'StackValidationFailed: Property error : WebServer: '
|
|
'image Error validating value \'1\': '
|
|
'The Image (1) could not be found.',
|
|
six.text_type(error))
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_create_unexpected_status(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._create_test_server(return_server,
|
|
'cr_unexp_sts')
|
|
return_server.get = lambda: None
|
|
return_server.status = 'BOGUS'
|
|
self.assertRaises(exception.Error,
|
|
server.check_create_complete,
|
|
return_server)
|
|
|
|
def test_server_create_error_status(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._create_test_server(return_server,
|
|
'cr_err_sts')
|
|
return_server.status = 'ERROR'
|
|
return_server.fault = {
|
|
'message': 'NoValidHost',
|
|
'code': 500,
|
|
'created': '2013-08-14T03:12:10Z'
|
|
}
|
|
self.m.StubOutWithMock(return_server, 'get')
|
|
return_server.get()
|
|
self.m.ReplayAll()
|
|
|
|
self.assertRaises(exception.Error,
|
|
server.check_create_complete,
|
|
return_server)
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_create_raw_userdata(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
stack_name = 'raw_userdata_s'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
tmpl['Resources']['WebServer']['Properties']['user_data_format'] = \
|
|
'RAW'
|
|
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('WebServer',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', 744)
|
|
|
|
self.m.StubOutWithMock(self.fc.servers, 'create')
|
|
self.fc.servers.create(
|
|
image=744, flavor=3, key_name='test',
|
|
name=utils.PhysName(stack_name, server.name),
|
|
security_groups=[],
|
|
userdata='wordpress', scheduler_hints=None,
|
|
meta=None, nics=None, availability_zone=None,
|
|
block_device_mapping=None, config_drive=None,
|
|
disk_config=None, reservation_id=None, files={},
|
|
admin_pass=None).AndReturn(
|
|
return_server)
|
|
|
|
self.m.ReplayAll()
|
|
scheduler.TaskRunner(server.create)()
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_create_raw_config_userdata(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
stack_name = 'raw_userdata_s'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
tmpl['Resources']['WebServer']['Properties']['user_data_format'] = \
|
|
'RAW'
|
|
tmpl['Resources']['WebServer']['Properties']['user_data'] = \
|
|
'8c813873-f6ee-4809-8eec-959ef39acb55'
|
|
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('WebServer',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
self.m.StubOutWithMock(server, 'heat')
|
|
self.m.StubOutWithMock(sc.SoftwareConfig, 'get_software_config')
|
|
server.heat().AndReturn(None)
|
|
sc.SoftwareConfig.get_software_config(
|
|
None, '8c813873-f6ee-4809-8eec-959ef39acb55').AndReturn(
|
|
'wordpress from config')
|
|
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', 744)
|
|
|
|
self.m.StubOutWithMock(self.fc.servers, 'create')
|
|
self.fc.servers.create(
|
|
image=744, flavor=3, key_name='test',
|
|
name=utils.PhysName(stack_name, server.name),
|
|
security_groups=[],
|
|
userdata='wordpress from config', scheduler_hints=None,
|
|
meta=None, nics=None, availability_zone=None,
|
|
block_device_mapping=None, config_drive=None,
|
|
disk_config=None, reservation_id=None, files={},
|
|
admin_pass=None).AndReturn(
|
|
return_server)
|
|
|
|
self.m.ReplayAll()
|
|
scheduler.TaskRunner(server.create)()
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_create_raw_config_userdata_None(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
stack_name = 'raw_userdata_s'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
sc_id = '8c813873-f6ee-4809-8eec-959ef39acb55'
|
|
tmpl['Resources']['WebServer']['Properties']['user_data_format'] = \
|
|
'RAW'
|
|
tmpl['Resources']['WebServer']['Properties']['user_data'] = sc_id
|
|
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('WebServer',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
self.m.StubOutWithMock(server, 'heat')
|
|
self.m.StubOutWithMock(sc.SoftwareConfig, 'get_software_config')
|
|
server.heat().AndReturn(None)
|
|
sc.SoftwareConfig.get_software_config(
|
|
None, sc_id).AndRaise(exception.SoftwareConfigMissing(
|
|
software_config_id=sc_id))
|
|
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', 744)
|
|
|
|
self.m.StubOutWithMock(self.fc.servers, 'create')
|
|
self.fc.servers.create(
|
|
image=744, flavor=3, key_name='test',
|
|
name=utils.PhysName(stack_name, server.name),
|
|
security_groups=[],
|
|
userdata=sc_id,
|
|
scheduler_hints=None, meta=None,
|
|
nics=None, availability_zone=None,
|
|
block_device_mapping=None, config_drive=None,
|
|
disk_config=None, reservation_id=None, files={},
|
|
admin_pass=None).AndReturn(return_server)
|
|
|
|
self.m.ReplayAll()
|
|
scheduler.TaskRunner(server.create)()
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_create_software_config(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
stack_name = 'software_config_s'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
tmpl['Resources']['WebServer']['Properties']['user_data_format'] = \
|
|
'SOFTWARE_CONFIG'
|
|
|
|
stack.stack_user_project_id = '8888'
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('WebServer',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
self.m.StubOutWithMock(server, 'heat')
|
|
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', 744)
|
|
|
|
self.m.StubOutWithMock(self.fc.servers, 'create')
|
|
self.fc.servers.create(
|
|
image=744, flavor=3, key_name='test',
|
|
name=utils.PhysName(stack_name, server.name),
|
|
security_groups=[],
|
|
userdata=mox.IgnoreArg(), scheduler_hints=None,
|
|
meta=None, nics=None, availability_zone=None,
|
|
block_device_mapping=None, config_drive=None,
|
|
disk_config=None, reservation_id=None, files={},
|
|
admin_pass=None).AndReturn(
|
|
return_server)
|
|
|
|
self.m.ReplayAll()
|
|
scheduler.TaskRunner(server.create)()
|
|
|
|
self.assertEqual('4567', server.access_key)
|
|
self.assertEqual('8901', server.secret_key)
|
|
self.assertEqual('1234', server._get_user_id())
|
|
|
|
self.assertTrue(stack.access_allowed('4567', 'WebServer'))
|
|
self.assertFalse(stack.access_allowed('45678', 'WebServer'))
|
|
self.assertFalse(stack.access_allowed('4567', 'wWebServer'))
|
|
|
|
self.assertEqual({
|
|
'os-collect-config': {
|
|
'cfn': {
|
|
'access_key_id': '4567',
|
|
'metadata_url': '/v1/',
|
|
'path': 'WebServer.Metadata',
|
|
'secret_access_key': '8901',
|
|
'stack_name': 'software_config_s'
|
|
}
|
|
},
|
|
'deployments': []
|
|
}, server.metadata_get())
|
|
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
created_server = servers.Server('WebServer',
|
|
resource_defns['WebServer'], stack)
|
|
self.assertEqual('4567', created_server.access_key)
|
|
self.assertTrue(stack.access_allowed('4567', 'WebServer'))
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_create_software_config_poll_heat(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
stack_name = 'software_config_s'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
props = tmpl.t['Resources']['WebServer']['Properties']
|
|
props['user_data_format'] = 'SOFTWARE_CONFIG'
|
|
props['software_config_transport'] = 'POLL_SERVER_HEAT'
|
|
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('WebServer',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', 744)
|
|
|
|
self.m.StubOutWithMock(self.fc.servers, 'create')
|
|
self.fc.servers.create(
|
|
image=744, flavor=3, key_name='test',
|
|
name=utils.PhysName(stack_name, server.name),
|
|
security_groups=[],
|
|
userdata=mox.IgnoreArg(), scheduler_hints=None,
|
|
meta=None, nics=None, availability_zone=None,
|
|
block_device_mapping=None, config_drive=None,
|
|
disk_config=None, reservation_id=None, files={},
|
|
admin_pass=None).AndReturn(
|
|
return_server)
|
|
|
|
self.m.ReplayAll()
|
|
scheduler.TaskRunner(server.create)()
|
|
|
|
#self.assertEqual('4567', server.access_key)
|
|
#self.assertEqual('8901', server.secret_key)
|
|
self.assertEqual('1234', server._get_user_id())
|
|
|
|
self.assertTrue(stack.access_allowed('1234', 'WebServer'))
|
|
self.assertFalse(stack.access_allowed('45678', 'WebServer'))
|
|
self.assertFalse(stack.access_allowed('4567', 'wWebServer'))
|
|
|
|
self.assertEqual({
|
|
'os-collect-config': {
|
|
'heat': {
|
|
'auth_url': 'http://server.test:5000/v2.0',
|
|
'password': server.password,
|
|
'project_id': '8888',
|
|
'resource_name': 'WebServer',
|
|
'stack_id': 'software_config_s/%s' % stack.id,
|
|
'user_id': '1234'
|
|
}
|
|
},
|
|
'deployments': []
|
|
}, server.metadata_get())
|
|
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
created_server = servers.Server('WebServer',
|
|
resource_defns['WebServer'], stack)
|
|
self.assertEqual('1234', created_server._get_user_id())
|
|
self.assertTrue(stack.access_allowed('1234', 'WebServer'))
|
|
|
|
self.m.VerifyAll()
|
|
|
|
@mock.patch.object(nova.NovaClientPlugin, '_create')
|
|
def test_server_create_default_admin_pass(self, mock_client):
|
|
return_server = self.fc.servers.list()[1]
|
|
return_server.adminPass = 'autogenerated'
|
|
stack_name = 'admin_pass_s'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('WebServer',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
mock_client.return_value = self.fc
|
|
self.fc.servers.create = mock.Mock(return_value=return_server)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', 744)
|
|
|
|
scheduler.TaskRunner(server.create)()
|
|
self.fc.servers.create(
|
|
image=744, flavor=3, key_name='test',
|
|
name=utils.PhysName(stack_name, server.name),
|
|
security_groups=[],
|
|
userdata=mock.ANY, scheduler_hints=None,
|
|
meta=None, nics=None, availability_zone=None,
|
|
block_device_mapping=None, config_drive=None,
|
|
disk_config=None, reservation_id=None,
|
|
files={}, admin_pass=None)
|
|
|
|
@mock.patch.object(nova.NovaClientPlugin, '_create')
|
|
def test_server_create_custom_admin_pass(self, mock_client):
|
|
return_server = self.fc.servers.list()[1]
|
|
return_server.adminPass = 'foo'
|
|
stack_name = 'admin_pass_s'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
tmpl.t['Resources']['WebServer']['Properties']['admin_pass'] = 'foo'
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('WebServer',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
mock_client.return_value = self.fc
|
|
self.fc.servers.create = mock.Mock(return_value=return_server)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', 744)
|
|
|
|
scheduler.TaskRunner(server.create)()
|
|
self.fc.servers.create(
|
|
image=744, flavor=3, key_name='test',
|
|
name=utils.PhysName(stack_name, server.name),
|
|
security_groups=[],
|
|
userdata=mock.ANY, scheduler_hints=None,
|
|
meta=None, nics=None, availability_zone=None,
|
|
block_device_mapping=None, config_drive=None,
|
|
disk_config=None, reservation_id=None,
|
|
files={}, admin_pass='foo')
|
|
|
|
def test_check_maximum(self):
|
|
msg = 'test_check_maximum'
|
|
self.assertIsNone(servers.Server._check_maximum(1, 1, msg))
|
|
self.assertIsNone(servers.Server._check_maximum(1000, -1, msg))
|
|
error = self.assertRaises(exception.StackValidationFailed,
|
|
servers.Server._check_maximum,
|
|
2, 1, msg)
|
|
self.assertEqual(msg, six.text_type(error))
|
|
|
|
def test_server_validate(self):
|
|
stack_name = 'srv_val'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
tmpl.t['Resources']['WebServer']['Properties']['image'] = '1'
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('server_create_image',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self._mock_get_image_id_success('1', 1)
|
|
|
|
self.m.ReplayAll()
|
|
|
|
self.assertIsNone(server.validate())
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_validate_with_bootable_vol(self):
|
|
stack_name = 'srv_val_bootvol'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
# create an server with bootable volume
|
|
web_server = tmpl.t['Resources']['WebServer']
|
|
del web_server['Properties']['image']
|
|
|
|
def create_server(device_name, mock_create=True):
|
|
self.m.UnsetStubs()
|
|
web_server['Properties']['block_device_mapping'] = [{
|
|
"device_name": device_name,
|
|
"volume_id": "5d7e27da-6703-4f7e-9f94-1f67abef734c",
|
|
"delete_on_termination": False
|
|
}]
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('server_with_bootable_volume',
|
|
resource_defns['WebServer'], stack)
|
|
if mock_create:
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self.m.ReplayAll()
|
|
return server
|
|
|
|
server = create_server(u'vda')
|
|
self.assertIsNone(server.validate())
|
|
server = create_server('vda', mock_create=False)
|
|
self.assertIsNone(server.validate())
|
|
server = create_server('vdb', mock_create=False)
|
|
ex = self.assertRaises(exception.StackValidationFailed,
|
|
server.validate)
|
|
self.assertEqual('Neither image nor bootable volume is specified for '
|
|
'instance server_with_bootable_volume',
|
|
six.text_type(ex))
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_validate_with_nova_keypair_resource(self):
|
|
stack_name = 'srv_val_test'
|
|
nova_keypair_template = '''
|
|
{
|
|
"AWSTemplateFormatVersion" : "2010-09-09",
|
|
"Description" : "WordPress",
|
|
"Resources" : {
|
|
"WebServer": {
|
|
"Type": "OS::Nova::Server",
|
|
"Properties": {
|
|
"image" : "F17-x86_64-gold",
|
|
"flavor" : "m1.large",
|
|
"key_name" : { "Ref": "SSHKey" },
|
|
"user_data" : "wordpress"
|
|
}
|
|
},
|
|
"SSHKey": {
|
|
"Type": "OS::Nova::KeyPair",
|
|
"Properties": {
|
|
"name": "my_key"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
'''
|
|
t = template_format.parse(nova_keypair_template)
|
|
template = parser.Template(t)
|
|
stack = parser.Stack(utils.dummy_context(), stack_name, template,
|
|
stack_id=str(uuid.uuid4()))
|
|
|
|
resource_defns = template.resource_definitions(stack)
|
|
server = servers.Server('server_validate_test',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
self.m.StubOutWithMock(glance.ImageConstraint, "validate")
|
|
glance.ImageConstraint.validate(
|
|
mox.IgnoreArg(), mox.IgnoreArg()).MultipleTimes().AndReturn(True)
|
|
self.m.ReplayAll()
|
|
self.m.ReplayAll()
|
|
|
|
self.assertIsNone(server.validate())
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_validate_with_invalid_ssh_key(self):
|
|
stack_name = 'srv_val_test'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
web_server = tmpl['Resources']['WebServer']
|
|
|
|
# Make the ssh key have an invalid name
|
|
web_server['Properties']['key_name'] = 'test2'
|
|
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('WebServer',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self.m.ReplayAll()
|
|
|
|
error = self.assertRaises(exception.StackValidationFailed,
|
|
server.validate)
|
|
self.assertEqual(
|
|
'Property error : WebServer: key_name Error validating '
|
|
'value \'test2\': The Key (test2) could not be found.',
|
|
six.text_type(error))
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_validate_with_networks(self):
|
|
stack_name = 'srv_net'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
network_name = 'public'
|
|
# create an server with 'uuid' and 'network' properties
|
|
tmpl['Resources']['WebServer']['Properties']['networks'] = (
|
|
[{'uuid': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'network': network_name}])
|
|
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('server_validate_with_networks',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', 'image_id')
|
|
|
|
self.m.ReplayAll()
|
|
|
|
ex = self.assertRaises(exception.StackValidationFailed,
|
|
server.validate)
|
|
self.assertIn(_('Properties "uuid" and "network" are both set to '
|
|
'the network "%(network)s" for the server '
|
|
'"%(server)s". The "uuid" property is deprecated. '
|
|
'Use only "network" property.'
|
|
'') % dict(network=network_name, server=server.name),
|
|
six.text_type(ex))
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_validate_net_security_groups(self):
|
|
# Test that if network 'ports' are assigned security groups are
|
|
# not, because they'll be ignored
|
|
stack_name = 'srv_net_secgroups'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
tmpl['Resources']['WebServer']['Properties']['networks'] = [
|
|
{'port': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'}]
|
|
tmpl['Resources']['WebServer']['Properties']['security_groups'] = \
|
|
['my_security_group']
|
|
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('server_validate_net_security_groups',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
|
|
self._mock_get_image_id_success('F17-x86_64-gold', 'image_id')
|
|
self.m.ReplayAll()
|
|
|
|
error = self.assertRaises(exception.ResourcePropertyConflict,
|
|
server.validate)
|
|
self.assertEqual("Cannot define the following properties at the same "
|
|
"time: security_groups, networks/port.",
|
|
six.text_type(error))
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_delete(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._create_test_server(return_server,
|
|
'create_delete')
|
|
server.resource_id = '1234'
|
|
|
|
# this makes sure the auto increment worked on server creation
|
|
self.assertTrue(server.id > 0)
|
|
|
|
server_get = self.fc.client.get_servers_1234()
|
|
self.m.StubOutWithMock(self.fc.client, 'get_servers_1234')
|
|
get = self.fc.client.get_servers_1234
|
|
get().AndReturn(server_get)
|
|
get().AndRaise(fakes_v1_1.fake_exception())
|
|
mox.Replay(get)
|
|
self.m.ReplayAll()
|
|
|
|
scheduler.TaskRunner(server.delete)()
|
|
self.assertIsNone(server.resource_id)
|
|
self.assertEqual((server.DELETE, server.COMPLETE), server.state)
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_delete_notfound(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._create_test_server(return_server,
|
|
'create_delete2')
|
|
server.resource_id = '1234'
|
|
|
|
# this makes sure the auto increment worked on server creation
|
|
self.assertTrue(server.id > 0)
|
|
|
|
self.m.StubOutWithMock(self.fc.client, 'get_servers_1234')
|
|
get = self.fc.client.get_servers_1234
|
|
get().AndRaise(fakes_v1_1.fake_exception())
|
|
mox.Replay(get)
|
|
|
|
scheduler.TaskRunner(server.delete)()
|
|
self.assertIsNone(server.resource_id)
|
|
self.assertEqual((server.DELETE, server.COMPLETE), server.state)
|
|
self.m.VerifyAll()
|
|
|
|
server.state_set(server.CREATE, server.COMPLETE, 'to delete again')
|
|
scheduler.TaskRunner(server.delete)()
|
|
self.assertEqual((server.DELETE, server.COMPLETE), server.state)
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_delete_error(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._create_test_server(return_server,
|
|
'create_delete')
|
|
server.resource_id = '1234'
|
|
|
|
# this makes sure the auto increment worked on server creation
|
|
self.assertTrue(server.id > 0)
|
|
|
|
server_get = self.fc.client.get_servers_1234()
|
|
self.m.StubOutWithMock(self.fc.client, 'get_servers_1234')
|
|
|
|
def make_error():
|
|
server_get[1]["server"]['status'] = "ERROR"
|
|
|
|
get = self.fc.client.get_servers_1234
|
|
get().AndReturn(server_get)
|
|
get().AndReturn(server_get)
|
|
get().WithSideEffects(make_error).AndReturn(server_get)
|
|
mox.Replay(get)
|
|
|
|
resf = self.assertRaises(exception.ResourceFailure,
|
|
scheduler.TaskRunner(server.delete))
|
|
self.assertIn("Server sample-server delete failed",
|
|
six.text_type(resf))
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_update_metadata(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._create_test_server(return_server,
|
|
'md_update')
|
|
|
|
ud_tmpl = self._get_test_template('update_stack')[0]
|
|
ud_tmpl.t['Resources']['WebServer']['Metadata'] = {'test': 123}
|
|
resource_defns = ud_tmpl.resource_definitions(server.stack)
|
|
scheduler.TaskRunner(server.update, resource_defns['WebServer'])()
|
|
self.assertEqual({'test': 123}, server.metadata_get())
|
|
|
|
ud_tmpl.t['Resources']['WebServer']['Metadata'] = {'test': 456}
|
|
server.t = ud_tmpl.resource_definitions(server.stack)['WebServer']
|
|
|
|
self.assertEqual({'test': 123}, server.metadata_get())
|
|
server.metadata_update()
|
|
self.assertEqual({'test': 456}, server.metadata_get())
|
|
|
|
def test_server_update_nova_metadata(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._create_test_server(return_server,
|
|
'md_update')
|
|
|
|
new_meta = {'test': 123}
|
|
self.m.StubOutWithMock(self.fc.servers, 'set_meta')
|
|
self.fc.servers.set_meta(return_server,
|
|
nova_utils.meta_serialize(
|
|
new_meta)).AndReturn(None)
|
|
self.m.ReplayAll()
|
|
update_template = copy.deepcopy(server.t)
|
|
update_template['Properties']['metadata'] = new_meta
|
|
scheduler.TaskRunner(server.update, update_template)()
|
|
self.assertEqual((server.UPDATE, server.COMPLETE), server.state)
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_update_nova_metadata_complex(self):
|
|
"""
|
|
Test that complex metadata values are correctly serialized
|
|
to JSON when sent to Nova.
|
|
"""
|
|
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._create_test_server(return_server,
|
|
'md_update')
|
|
|
|
new_meta = {'test': {'testkey': 'testvalue'}}
|
|
self.m.StubOutWithMock(self.fc.servers, 'set_meta')
|
|
|
|
# If we're going to call set_meta() directly we
|
|
# need to handle the serialization ourselves.
|
|
self.fc.servers.set_meta(return_server,
|
|
nova_utils.meta_serialize(
|
|
new_meta)).AndReturn(None)
|
|
self.m.ReplayAll()
|
|
update_template = copy.deepcopy(server.t)
|
|
update_template['Properties']['metadata'] = new_meta
|
|
scheduler.TaskRunner(server.update, update_template)()
|
|
self.assertEqual((server.UPDATE, server.COMPLETE), server.state)
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_update_nova_metadata_with_delete(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._create_test_server(return_server,
|
|
'md_update')
|
|
|
|
# part one, add some metadata
|
|
new_meta = {'test': '123', 'this': 'that'}
|
|
self.m.StubOutWithMock(self.fc.servers, 'set_meta')
|
|
self.fc.servers.set_meta(return_server,
|
|
new_meta).AndReturn(None)
|
|
self.m.ReplayAll()
|
|
update_template = copy.deepcopy(server.t)
|
|
update_template['Properties']['metadata'] = new_meta
|
|
scheduler.TaskRunner(server.update, update_template)()
|
|
self.assertEqual((server.UPDATE, server.COMPLETE), server.state)
|
|
self.m.VerifyAll()
|
|
self.m.UnsetStubs()
|
|
|
|
# part two change the metadata (test removing the old key)
|
|
self.m.ReplayAll()
|
|
new_meta = {'new_key': 'yeah'}
|
|
|
|
self.m.StubOutWithMock(self.fc.servers, 'delete_meta')
|
|
new_return_server = self.fc.servers.list()[5]
|
|
self.fc.servers.delete_meta(new_return_server,
|
|
['test', 'this']).AndReturn(None)
|
|
|
|
self.m.StubOutWithMock(self.fc.servers, 'set_meta')
|
|
self.fc.servers.set_meta(new_return_server,
|
|
new_meta).AndReturn(None)
|
|
self._mock_get_image_id_success('CentOS 5.2', 1)
|
|
self.m.ReplayAll()
|
|
update_template = copy.deepcopy(server.t)
|
|
update_template['Properties']['metadata'] = new_meta
|
|
|
|
# new fake with the correct metadata
|
|
server.resource_id = '56789'
|
|
|
|
scheduler.TaskRunner(server.update, update_template)()
|
|
self.assertEqual((server.UPDATE, server.COMPLETE), server.state)
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_update_server_name(self):
|
|
"""
|
|
Server.handle_update supports changing the name.
|
|
"""
|
|
return_server = self.fc.servers.list()[1]
|
|
return_server.id = '5678'
|
|
server = self._create_test_server(return_server,
|
|
'srv_update')
|
|
new_name = 'new_name'
|
|
update_template = copy.deepcopy(server.t)
|
|
update_template['Properties']['name'] = new_name
|
|
|
|
self.m.StubOutWithMock(self.fc.servers, 'get')
|
|
self.fc.servers.get('5678').AndReturn(return_server)
|
|
|
|
self.m.StubOutWithMock(return_server, 'update')
|
|
return_server.update(new_name).AndReturn(None)
|
|
self.m.ReplayAll()
|
|
scheduler.TaskRunner(server.update, update_template)()
|
|
self.assertEqual((server.UPDATE, server.COMPLETE), server.state)
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_update_server_flavor(self):
|
|
"""
|
|
Server.handle_update supports changing the flavor, and makes
|
|
the change making a resize API call against Nova.
|
|
"""
|
|
return_server = self.fc.servers.list()[1]
|
|
return_server.id = '1234'
|
|
server = self._create_test_server(return_server,
|
|
'srv_update')
|
|
|
|
update_template = copy.deepcopy(server.t)
|
|
update_template['Properties']['flavor'] = 'm1.small'
|
|
|
|
self.m.StubOutWithMock(self.fc.servers, 'get')
|
|
self.fc.servers.get('1234').AndReturn(return_server)
|
|
|
|
def activate_status(server):
|
|
server.status = 'VERIFY_RESIZE'
|
|
return_server.get = activate_status.__get__(return_server)
|
|
|
|
self.m.StubOutWithMock(self.fc.client, 'post_servers_1234_action')
|
|
self.fc.client.post_servers_1234_action(
|
|
body={'resize': {'flavorRef': 2}}).AndReturn((202, None))
|
|
self.fc.client.post_servers_1234_action(
|
|
body={'confirmResize': None}).AndReturn((202, None))
|
|
self.m.ReplayAll()
|
|
|
|
scheduler.TaskRunner(server.update, update_template)()
|
|
self.assertEqual((server.UPDATE, server.COMPLETE), server.state)
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_update_server_flavor_failed(self):
|
|
"""
|
|
If the status after a resize is not VERIFY_RESIZE, it means the resize
|
|
call failed, so we raise an explicit error.
|
|
"""
|
|
return_server = self.fc.servers.list()[1]
|
|
return_server.id = '1234'
|
|
server = self._create_test_server(return_server,
|
|
'srv_update2')
|
|
|
|
update_template = copy.deepcopy(server.t)
|
|
update_template['Properties']['flavor'] = 'm1.small'
|
|
|
|
self.m.StubOutWithMock(self.fc.servers, 'get')
|
|
self.fc.servers.get('1234').AndReturn(return_server)
|
|
|
|
def activate_status(server):
|
|
server.status = 'ACTIVE'
|
|
return_server.get = activate_status.__get__(return_server)
|
|
|
|
self.m.StubOutWithMock(self.fc.client, 'post_servers_1234_action')
|
|
self.fc.client.post_servers_1234_action(
|
|
body={'resize': {'flavorRef': 2}}).AndReturn((202, None))
|
|
self.m.ReplayAll()
|
|
|
|
updater = scheduler.TaskRunner(server.update, update_template)
|
|
error = self.assertRaises(exception.ResourceFailure, updater)
|
|
self.assertEqual(
|
|
"Error: Resizing to 'm1.small' failed, status 'ACTIVE'",
|
|
six.text_type(error))
|
|
self.assertEqual((server.UPDATE, server.FAILED), server.state)
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_update_server_flavor_replace(self):
|
|
stack_name = 'update_flvrep'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', 'image_id')
|
|
self.m.ReplayAll()
|
|
|
|
tmpl['Resources']['WebServer']['Properties'][
|
|
'flavor_update_policy'] = 'REPLACE'
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('server_server_update_flavor_replace',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
update_template = copy.deepcopy(server.t)
|
|
update_template['Properties']['flavor'] = 'm1.smigish'
|
|
updater = scheduler.TaskRunner(server.update, update_template)
|
|
self.assertRaises(resource.UpdateReplace, updater)
|
|
|
|
def test_server_update_server_flavor_policy_update(self):
|
|
stack_name = 'update_flvpol'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', 'image_id')
|
|
self.m.ReplayAll()
|
|
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('server_server_update_flavor_replace',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
update_template = copy.deepcopy(server.t)
|
|
# confirm that when flavor_update_policy is changed during
|
|
# the update then the updated policy is followed for a flavor
|
|
# update
|
|
update_template['Properties']['flavor_update_policy'] = 'REPLACE'
|
|
update_template['Properties']['flavor'] = 'm1.smigish'
|
|
updater = scheduler.TaskRunner(server.update, update_template)
|
|
self.assertRaises(resource.UpdateReplace, updater)
|
|
|
|
def test_server_update_image_replace(self):
|
|
stack_name = 'update_imgrep'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
tmpl.t['Resources']['WebServer']['Properties'][
|
|
'image_update_policy'] = 'REPLACE'
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('server_update_image_replace',
|
|
resource_defns['WebServer'], stack)
|
|
image_id = self.getUniqueString()
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self.m.StubOutWithMock(glance.ImageConstraint, "validate")
|
|
glance.ImageConstraint.validate(
|
|
mox.IgnoreArg(), mox.IgnoreArg()).MultipleTimes().AndReturn(True)
|
|
self.m.ReplayAll()
|
|
|
|
update_template = copy.deepcopy(server.t)
|
|
update_template['Properties']['image'] = image_id
|
|
updater = scheduler.TaskRunner(server.update, update_template)
|
|
self.assertRaises(resource.UpdateReplace, updater)
|
|
|
|
def _test_server_update_image_rebuild(self, status, policy='REBUILD'):
|
|
# Server.handle_update supports changing the image, and makes
|
|
# the change making a rebuild API call against Nova.
|
|
return_server = self.fc.servers.list()[1]
|
|
return_server.id = '1234'
|
|
server = self._create_test_server(return_server,
|
|
'srv_updimgrbld',
|
|
server_rebuild=True)
|
|
|
|
new_image = 'F17-x86_64-gold'
|
|
# current test demonstrate updating when image_update_policy was not
|
|
# changed, so image_update_policy will be used from self.properties
|
|
server.t['Properties']['image_update_policy'] = policy
|
|
update_template = copy.deepcopy(server.t)
|
|
update_template['Properties']['image'] = new_image
|
|
|
|
self.m.StubOutWithMock(self.fc.servers, 'get')
|
|
self.fc.servers.get('1234').MultipleTimes().AndReturn(return_server)
|
|
self.m.StubOutWithMock(self.fc.servers, 'rebuild')
|
|
# 744 is a static lookup from the fake images list
|
|
if 'REBUILD' == policy:
|
|
self.fc.servers.rebuild(
|
|
return_server, 744, password=None, preserve_ephemeral=False)
|
|
else:
|
|
self.fc.servers.rebuild(
|
|
return_server, 744, password=None, preserve_ephemeral=True)
|
|
self.m.StubOutWithMock(self.fc.client, 'post_servers_1234_action')
|
|
for stat in status:
|
|
def activate_status(serv):
|
|
serv.status = stat
|
|
return_server.get = activate_status.__get__(return_server)
|
|
|
|
self.m.ReplayAll()
|
|
scheduler.TaskRunner(server.update, update_template)()
|
|
self.assertEqual((server.UPDATE, server.COMPLETE), server.state)
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_update_image_rebuild_status_rebuild(self):
|
|
# Normally we will see 'REBUILD' first and then 'ACTIVE".
|
|
self._test_server_update_image_rebuild(status=('REBUILD', 'ACTIVE'))
|
|
|
|
def test_server_update_image_rebuild_status_active(self):
|
|
# It is possible for us to miss the REBUILD status.
|
|
self._test_server_update_image_rebuild(status=('ACTIVE',))
|
|
|
|
def test_server_update_image_rebuild_status_rebuild_keep_ephemeral(self):
|
|
# Normally we will see 'REBUILD' first and then 'ACTIVE".
|
|
self._test_server_update_image_rebuild(
|
|
policy='REBUILD_PRESERVE_EPHEMERAL', status=('REBUILD', 'ACTIVE'))
|
|
|
|
def test_server_update_image_rebuild_status_active_keep_ephemeral(self):
|
|
# It is possible for us to miss the REBUILD status.
|
|
self._test_server_update_image_rebuild(
|
|
policy='REBUILD_PRESERVE_EPHEMERAL', status=('ACTIVE'))
|
|
|
|
def test_server_update_image_rebuild_failed(self):
|
|
# If the status after a rebuild is not REBUILD or ACTIVE, it means the
|
|
# rebuild call failed, so we raise an explicit error.
|
|
return_server = self.fc.servers.list()[1]
|
|
return_server.id = '1234'
|
|
server = self._create_test_server(return_server,
|
|
'srv_updrbldfail',
|
|
server_rebuild=True)
|
|
|
|
new_image = 'F17-x86_64-gold'
|
|
# current test demonstrate updating when image_update_policy was not
|
|
# changed, so image_update_policy will be used from self.properties
|
|
server.t['Properties']['image_update_policy'] = 'REBUILD'
|
|
update_template = copy.deepcopy(server.t)
|
|
update_template['Properties']['image'] = new_image
|
|
|
|
self.m.StubOutWithMock(self.fc.servers, 'get')
|
|
self.fc.servers.get('1234').MultipleTimes().AndReturn(return_server)
|
|
self.m.StubOutWithMock(self.fc.servers, 'rebuild')
|
|
# 744 is a static lookup from the fake images list
|
|
self.fc.servers.rebuild(
|
|
return_server, 744, password=None, preserve_ephemeral=False)
|
|
self.m.StubOutWithMock(self.fc.client, 'post_servers_1234_action')
|
|
|
|
def activate_status(server):
|
|
server.status = 'REBUILD'
|
|
return_server.get = activate_status.__get__(return_server)
|
|
|
|
def activate_status2(server):
|
|
server.status = 'ERROR'
|
|
return_server.get = activate_status2.__get__(return_server)
|
|
self.m.ReplayAll()
|
|
updater = scheduler.TaskRunner(server.update, update_template)
|
|
error = self.assertRaises(exception.ResourceFailure, updater)
|
|
self.assertEqual(
|
|
"Error: Rebuilding server failed, status 'ERROR'",
|
|
six.text_type(error))
|
|
self.assertEqual((server.UPDATE, server.FAILED), server.state)
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_update_properties(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._create_test_server(return_server,
|
|
'update_prop')
|
|
|
|
self.m.StubOutWithMock(glance.ImageConstraint, "validate")
|
|
glance.ImageConstraint.validate(
|
|
mox.IgnoreArg(), mox.IgnoreArg()).MultipleTimes().AndReturn(True)
|
|
self.m.ReplayAll()
|
|
|
|
update_template = copy.deepcopy(server.t)
|
|
update_template['Properties']['image'] = 'mustreplace'
|
|
updater = scheduler.TaskRunner(server.update, update_template)
|
|
self.assertRaises(resource.UpdateReplace, updater)
|
|
|
|
def test_server_status_build(self):
|
|
return_server = self.fc.servers.list()[0]
|
|
server = self._setup_test_server(return_server,
|
|
'sts_build')
|
|
server.resource_id = '1234'
|
|
|
|
# Bind fake get method which Server.check_create_complete will call
|
|
def activate_status(server):
|
|
server.status = 'ACTIVE'
|
|
return_server.get = activate_status.__get__(return_server)
|
|
self.m.ReplayAll()
|
|
|
|
scheduler.TaskRunner(server.create)()
|
|
self.assertEqual((server.CREATE, server.COMPLETE), server.state)
|
|
|
|
def test_server_status_suspend_no_resource_id(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._create_test_server(return_server,
|
|
'srv_sus1')
|
|
|
|
server.resource_id = None
|
|
self.m.ReplayAll()
|
|
|
|
ex = self.assertRaises(exception.ResourceFailure,
|
|
scheduler.TaskRunner(server.suspend))
|
|
self.assertEqual('Error: Cannot suspend srv_sus1, '
|
|
'resource_id not set',
|
|
six.text_type(ex))
|
|
self.assertEqual((server.SUSPEND, server.FAILED), server.state)
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_status_suspend_not_found(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._create_test_server(return_server,
|
|
'srv_sus2')
|
|
|
|
server.resource_id = '1234'
|
|
self.m.StubOutWithMock(self.fc.client, 'get_servers_1234')
|
|
get = self.fc.client.get_servers_1234
|
|
get().AndRaise(fakes_v1_1.fake_exception())
|
|
mox.Replay(get)
|
|
self.m.ReplayAll()
|
|
|
|
ex = self.assertRaises(exception.ResourceFailure,
|
|
scheduler.TaskRunner(server.suspend))
|
|
self.assertEqual('NotFound: Failed to find server 1234',
|
|
six.text_type(ex))
|
|
self.assertEqual((server.SUSPEND, server.FAILED), server.state)
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_status_suspend_immediate(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._create_test_server(return_server,
|
|
'srv_suspend3')
|
|
|
|
server.resource_id = '1234'
|
|
self.m.ReplayAll()
|
|
|
|
# Override the get_servers_1234 handler status to SUSPENDED
|
|
d = {'server': self.fc.client.get_servers_detail()[1]['servers'][0]}
|
|
d['server']['status'] = 'SUSPENDED'
|
|
self.m.StubOutWithMock(self.fc.client, 'get_servers_1234')
|
|
get = self.fc.client.get_servers_1234
|
|
get().AndReturn((200, d))
|
|
mox.Replay(get)
|
|
|
|
scheduler.TaskRunner(server.suspend)()
|
|
self.assertEqual((server.SUSPEND, server.COMPLETE), server.state)
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_status_resume_immediate(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._create_test_server(return_server,
|
|
'srv_resume1')
|
|
|
|
server.resource_id = '1234'
|
|
self.m.ReplayAll()
|
|
|
|
# Override the get_servers_1234 handler status to SUSPENDED
|
|
d = {'server': self.fc.client.get_servers_detail()[1]['servers'][0]}
|
|
d['server']['status'] = 'ACTIVE'
|
|
self.m.StubOutWithMock(self.fc.client, 'get_servers_1234')
|
|
get = self.fc.client.get_servers_1234
|
|
get().AndReturn((200, d))
|
|
mox.Replay(get)
|
|
server.state_set(server.SUSPEND, server.COMPLETE)
|
|
|
|
scheduler.TaskRunner(server.resume)()
|
|
self.assertEqual((server.RESUME, server.COMPLETE), server.state)
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_status_suspend_wait(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._create_test_server(return_server,
|
|
'srv_susp_w')
|
|
|
|
server.resource_id = '1234'
|
|
self.m.ReplayAll()
|
|
|
|
# Override the get_servers_1234 handler status to SUSPENDED, but
|
|
# return the ACTIVE state first (twice, so we sleep)
|
|
d1 = {'server': self.fc.client.get_servers_detail()[1]['servers'][0]}
|
|
d2 = copy.deepcopy(d1)
|
|
d1['server']['status'] = 'ACTIVE'
|
|
d2['server']['status'] = 'SUSPENDED'
|
|
self.m.StubOutWithMock(self.fc.client, 'get_servers_1234')
|
|
get = self.fc.client.get_servers_1234
|
|
get().AndReturn((200, d1))
|
|
get().AndReturn((200, d1))
|
|
get().AndReturn((200, d2))
|
|
self.m.ReplayAll()
|
|
|
|
scheduler.TaskRunner(server.suspend)()
|
|
self.assertEqual((server.SUSPEND, server.COMPLETE), server.state)
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_status_suspend_unknown_status(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._create_test_server(return_server,
|
|
'srv_susp_uk')
|
|
|
|
server.resource_id = '1234'
|
|
self.m.ReplayAll()
|
|
|
|
# Override the get_servers_1234 handler status to SUSPENDED, but
|
|
# return the ACTIVE state first (twice, so we sleep)
|
|
d1 = {'server': self.fc.client.get_servers_detail()[1]['servers'][0]}
|
|
d2 = copy.deepcopy(d1)
|
|
d1['server']['status'] = 'ACTIVE'
|
|
d2['server']['status'] = 'TRANSMOGRIFIED'
|
|
self.m.StubOutWithMock(self.fc.client, 'get_servers_1234')
|
|
get = self.fc.client.get_servers_1234
|
|
get().AndReturn((200, d1))
|
|
get().AndReturn((200, d1))
|
|
get().AndReturn((200, d2))
|
|
self.m.ReplayAll()
|
|
|
|
ex = self.assertRaises(exception.ResourceFailure,
|
|
scheduler.TaskRunner(server.suspend))
|
|
self.assertEqual('Error: Suspend of server sample-server failed '
|
|
'with unknown status: TRANSMOGRIFIED',
|
|
six.text_type(ex))
|
|
self.assertEqual((server.SUSPEND, server.FAILED), server.state)
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_status_resume_wait(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._create_test_server(return_server,
|
|
'srv_res_w')
|
|
|
|
server.resource_id = '1234'
|
|
self.m.ReplayAll()
|
|
|
|
# Override the get_servers_1234 handler status to ACTIVE, but
|
|
# return the SUSPENDED state first (twice, so we sleep)
|
|
d1 = {'server': self.fc.client.get_servers_detail()[1]['servers'][0]}
|
|
d2 = copy.deepcopy(d1)
|
|
d1['server']['status'] = 'SUSPENDED'
|
|
d2['server']['status'] = 'ACTIVE'
|
|
self.m.StubOutWithMock(self.fc.client, 'get_servers_1234')
|
|
get = self.fc.client.get_servers_1234
|
|
get().AndReturn((200, d1))
|
|
get().AndReturn((200, d1))
|
|
get().AndReturn((200, d2))
|
|
self.m.ReplayAll()
|
|
|
|
server.state_set(server.SUSPEND, server.COMPLETE)
|
|
|
|
scheduler.TaskRunner(server.resume)()
|
|
self.assertEqual((server.RESUME, server.COMPLETE), server.state)
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_status_resume_no_resource_id(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._create_test_server(return_server,
|
|
'srv_susp_norid')
|
|
|
|
server.resource_id = None
|
|
self.m.ReplayAll()
|
|
|
|
server.state_set(server.SUSPEND, server.COMPLETE)
|
|
ex = self.assertRaises(exception.ResourceFailure,
|
|
scheduler.TaskRunner(server.resume))
|
|
self.assertEqual('Error: Cannot resume srv_susp_norid, '
|
|
'resource_id not set',
|
|
six.text_type(ex))
|
|
self.assertEqual((server.RESUME, server.FAILED), server.state)
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_status_resume_not_found(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._create_test_server(return_server,
|
|
'srv_res_nf')
|
|
|
|
server.resource_id = '1234'
|
|
self.m.ReplayAll()
|
|
|
|
# Override the get_servers_1234 handler status to ACTIVE, but
|
|
# return the SUSPENDED state first (twice, so we sleep)
|
|
self.m.StubOutWithMock(self.fc.client, 'get_servers_1234')
|
|
get = self.fc.client.get_servers_1234
|
|
get().AndRaise(fakes_v1_1.fake_exception())
|
|
self.m.ReplayAll()
|
|
|
|
server.state_set(server.SUSPEND, server.COMPLETE)
|
|
|
|
ex = self.assertRaises(exception.ResourceFailure,
|
|
scheduler.TaskRunner(server.resume))
|
|
self.assertEqual('NotFound: Failed to find server 1234',
|
|
six.text_type(ex))
|
|
self.assertEqual((server.RESUME, server.FAILED), server.state)
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_status_build_spawning(self):
|
|
self._test_server_status_not_build_active('BUILD(SPAWNING)')
|
|
|
|
def test_server_status_hard_reboot(self):
|
|
self._test_server_status_not_build_active('HARD_REBOOT')
|
|
|
|
def test_server_status_password(self):
|
|
self._test_server_status_not_build_active('PASSWORD')
|
|
|
|
def test_server_status_reboot(self):
|
|
self._test_server_status_not_build_active('REBOOT')
|
|
|
|
def test_server_status_rescue(self):
|
|
self._test_server_status_not_build_active('RESCUE')
|
|
|
|
def test_server_status_resize(self):
|
|
self._test_server_status_not_build_active('RESIZE')
|
|
|
|
def test_server_status_revert_resize(self):
|
|
self._test_server_status_not_build_active('REVERT_RESIZE')
|
|
|
|
def test_server_status_shutoff(self):
|
|
self._test_server_status_not_build_active('SHUTOFF')
|
|
|
|
def test_server_status_suspended(self):
|
|
self._test_server_status_not_build_active('SUSPENDED')
|
|
|
|
def test_server_status_verify_resize(self):
|
|
self._test_server_status_not_build_active('VERIFY_RESIZE')
|
|
|
|
def _test_server_status_not_build_active(self, uncommon_status):
|
|
return_server = self.fc.servers.list()[0]
|
|
server = self._setup_test_server(return_server,
|
|
'srv_sts_bld')
|
|
server.resource_id = '1234'
|
|
|
|
check_iterations = [0]
|
|
|
|
# Bind fake get method which Server.check_create_complete will call
|
|
def activate_status(server):
|
|
check_iterations[0] += 1
|
|
if check_iterations[0] == 1:
|
|
server.status = uncommon_status
|
|
if check_iterations[0] > 2:
|
|
server.status = 'ACTIVE'
|
|
return_server.get = activate_status.__get__(return_server)
|
|
self.m.ReplayAll()
|
|
|
|
scheduler.TaskRunner(server.create)()
|
|
self.assertEqual((server.CREATE, server.COMPLETE), server.state)
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_build_nics(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._create_test_server(return_server,
|
|
'test_server_create')
|
|
self.assertIsNone(server._build_nics([]))
|
|
self.assertIsNone(server._build_nics(None))
|
|
self.assertEqual([{'port-id': 'aaaabbbb'},
|
|
{'v4-fixed-ip': '192.0.2.0'}],
|
|
server._build_nics([{'port': 'aaaabbbb'},
|
|
{'fixed_ip': '192.0.2.0'}]))
|
|
|
|
self.assertEqual([{'net-id': '1234abcd'}],
|
|
server._build_nics([{'uuid': '1234abcd'}]))
|
|
|
|
self.assertEqual([{'net-id': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'}],
|
|
server._build_nics(
|
|
[{'network':
|
|
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'}]
|
|
))
|
|
|
|
self.assertEqual([{'net-id': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'}],
|
|
server._build_nics([{'network': 'public'}]))
|
|
|
|
self.assertRaises(nova_exceptions.NoUniqueMatch,
|
|
server._build_nics,
|
|
([{'network': 'foo'}]))
|
|
|
|
self.assertRaises(nova_exceptions.NotFound,
|
|
server._build_nics,
|
|
([{'network': 'bar'}]))
|
|
|
|
def test_server_without_ip_address(self):
|
|
return_server = self.fc.servers.list()[3]
|
|
return_server.id = '9102'
|
|
server = self._create_test_server(return_server,
|
|
'wo_ipaddr')
|
|
|
|
self.m.StubOutWithMock(self.fc.servers, 'get')
|
|
self.fc.servers.get('9102').MultipleTimes().AndReturn(return_server)
|
|
|
|
self.m.StubOutWithMock(return_server, 'interface_list')
|
|
return_server.interface_list().MultipleTimes().AndReturn([])
|
|
self.m.ReplayAll()
|
|
|
|
self.assertEqual({'empty_net': []}, server.FnGetAtt('addresses'))
|
|
self.assertEqual({'empty_net': []}, server.FnGetAtt('networks'))
|
|
self.assertEqual('', server.FnGetAtt('first_address'))
|
|
self.m.VerifyAll()
|
|
|
|
def test_build_block_device_mapping(self):
|
|
self.assertIsNone(servers.Server._build_block_device_mapping([]))
|
|
self.assertIsNone(servers.Server._build_block_device_mapping(None))
|
|
|
|
self.assertEqual({
|
|
'vda': '1234::',
|
|
'vdb': '1234:snap:',
|
|
}, servers.Server._build_block_device_mapping([
|
|
{'device_name': 'vda', 'volume_id': '1234'},
|
|
{'device_name': 'vdb', 'snapshot_id': '1234'},
|
|
]))
|
|
|
|
self.assertEqual({
|
|
'vdc': '1234::10',
|
|
'vdd': '1234:snap::True'
|
|
}, servers.Server._build_block_device_mapping([
|
|
{
|
|
'device_name': 'vdc',
|
|
'volume_id': '1234',
|
|
'volume_size': 10
|
|
},
|
|
{
|
|
'device_name': 'vdd',
|
|
'snapshot_id': '1234',
|
|
'delete_on_termination': True
|
|
}
|
|
]))
|
|
|
|
def test_validate_block_device_mapping_volume_size_valid_int(self):
|
|
stack_name = 'val_vsize_valid'
|
|
tmpl, stack = self._setup_test_stack(stack_name)
|
|
bdm = [{'device_name': 'vda', 'volume_id': '1234',
|
|
'volume_size': 10}]
|
|
wsp = tmpl.t['Resources']['WebServer']['Properties']
|
|
wsp['block_device_mapping'] = bdm
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('server_create_image_err',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
self._server_validate_mock(server)
|
|
self.m.ReplayAll()
|
|
|
|
self.assertIsNone(server.validate())
|
|
self.m.VerifyAll()
|
|
|
|
def test_validate_block_device_mapping_volume_size_valid_str(self):
|
|
stack_name = 'val_vsize_valid'
|
|
tmpl, stack = self._setup_test_stack(stack_name)
|
|
bdm = [{'device_name': 'vda', 'volume_id': '1234',
|
|
'volume_size': '10'}]
|
|
wsp = tmpl.t['Resources']['WebServer']['Properties']
|
|
wsp['block_device_mapping'] = bdm
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('server_create_image_err',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
self._server_validate_mock(server)
|
|
|
|
self.m.ReplayAll()
|
|
|
|
self.assertIsNone(server.validate())
|
|
self.m.VerifyAll()
|
|
|
|
def test_validate_block_device_mapping_volume_size_invalid_str(self):
|
|
stack_name = 'val_vsize_invalid'
|
|
tmpl, stack = self._setup_test_stack(stack_name)
|
|
bdm = [{'device_name': 'vda', 'volume_id': '1234',
|
|
'volume_size': '10a'}]
|
|
wsp = tmpl.t['Resources']['WebServer']['Properties']
|
|
wsp['block_device_mapping'] = bdm
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('server_create_image_err',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
exc = self.assertRaises(exception.StackValidationFailed,
|
|
server.validate)
|
|
self.assertIn("Value '10a' is not an integer", six.text_type(exc))
|
|
|
|
def test_validate_conflict_block_device_mapping_props(self):
|
|
stack_name = 'val_blkdev1'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
bdm = [{'device_name': 'vdb', 'snapshot_id': '1234',
|
|
'volume_id': '1234'}]
|
|
wsp = tmpl.t['Resources']['WebServer']['Properties']
|
|
wsp['block_device_mapping'] = bdm
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('server_create_image_err',
|
|
resource_defns['WebServer'], stack)
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', 'image_id')
|
|
self.m.ReplayAll()
|
|
|
|
self.assertRaises(exception.ResourcePropertyConflict, server.validate)
|
|
self.m.VerifyAll()
|
|
|
|
def test_validate_insufficient_block_device_mapping_props(self):
|
|
stack_name = 'val_blkdev2'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
bdm = [{'device_name': 'vdb', 'volume_size': 1,
|
|
'delete_on_termination': True}]
|
|
wsp = tmpl.t['Resources']['WebServer']['Properties']
|
|
wsp['block_device_mapping'] = bdm
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('server_create_image_err',
|
|
resource_defns['WebServer'], stack)
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', 'image_id')
|
|
self.m.ReplayAll()
|
|
|
|
ex = self.assertRaises(exception.StackValidationFailed,
|
|
server.validate)
|
|
msg = 'Either volume_id or snapshot_id must be specified for device' +\
|
|
' mapping vdb'
|
|
self.assertEqual(msg, six.text_type(ex))
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_validate_without_image_or_bootable_volume(self):
|
|
stack_name = 'val_imgvol'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
del tmpl['Resources']['WebServer']['Properties']['image']
|
|
bdm = [{'device_name': 'vdb', 'volume_id': '1234'}]
|
|
wsp = tmpl.t['Resources']['WebServer']['Properties']
|
|
wsp['block_device_mapping'] = bdm
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('server_create_image_err',
|
|
resource_defns['WebServer'], stack)
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self.m.ReplayAll()
|
|
|
|
ex = self.assertRaises(exception.StackValidationFailed,
|
|
server.validate)
|
|
msg = 'Neither image nor bootable volume is specified for instance %s'\
|
|
% server.name
|
|
self.assertEqual(msg, six.text_type(ex))
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_validate_metadata_too_many(self):
|
|
stack_name = 'srv_val_metadata'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
tmpl.t['Resources']['WebServer']['Properties']['metadata'] = {'a': 1,
|
|
'b': 2,
|
|
'c': 3,
|
|
'd': 4}
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('server_create_image_err',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
self.m.StubOutWithMock(self.fc.limits, 'get')
|
|
self.fc.limits.get().MultipleTimes().AndReturn(self.limits)
|
|
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', 'image_id')
|
|
self.m.ReplayAll()
|
|
|
|
ex = self.assertRaises(exception.StackValidationFailed,
|
|
server.validate)
|
|
self.assertIn('Instance metadata must not contain greater than 3 '
|
|
'entries', six.text_type(ex))
|
|
self.m.VerifyAll()
|
|
|
|
def test_validate_metadata_okay(self):
|
|
stack_name = 'srv_val_metadata'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
tmpl.t['Resources']['WebServer']['Properties']['metadata'] = {'a': 1,
|
|
'b': 2,
|
|
'c': 3}
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('server_create_image_err',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
self.m.StubOutWithMock(self.fc.limits, 'get')
|
|
self.fc.limits.get().MultipleTimes().AndReturn(self.limits)
|
|
|
|
self.m.StubOutWithMock(server, 'nova')
|
|
server.nova().MultipleTimes().AndReturn(self.fc)
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', 'image_id')
|
|
self.m.ReplayAll()
|
|
self.assertIsNone(server.validate())
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_validate_too_many_personality(self):
|
|
stack_name = 'srv_val'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
tmpl.t['Resources']['WebServer']['Properties']['personality'] = \
|
|
{"/fake/path1": "fake contents1",
|
|
"/fake/path2": "fake_contents2",
|
|
"/fake/path3": "fake_contents3",
|
|
"/fake/path4": "fake_contents4",
|
|
"/fake/path5": "fake_contents5",
|
|
"/fake/path6": "fake_contents6"}
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('server_create_image_err',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
self.m.StubOutWithMock(self.fc.limits, 'get')
|
|
self.fc.limits.get().MultipleTimes().AndReturn(self.limits)
|
|
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', 'image_id')
|
|
self.m.ReplayAll()
|
|
|
|
exc = self.assertRaises(exception.StackValidationFailed,
|
|
server.validate)
|
|
self.assertEqual("The personality property may not contain "
|
|
"greater than 5 entries.", six.text_type(exc))
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_validate_personality_okay(self):
|
|
stack_name = 'srv_val'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
tmpl.t['Resources']['WebServer']['Properties']['personality'] = \
|
|
{"/fake/path1": "fake contents1",
|
|
"/fake/path2": "fake_contents2",
|
|
"/fake/path3": "fake_contents3",
|
|
"/fake/path4": "fake_contents4",
|
|
"/fake/path5": "fake_contents5"}
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('server_create_image_err',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
self.m.StubOutWithMock(self.fc.limits, 'get')
|
|
self.fc.limits.get().MultipleTimes().AndReturn(self.limits)
|
|
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', 'image_id')
|
|
self.m.ReplayAll()
|
|
|
|
self.assertIsNone(server.validate())
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_validate_personality_file_size_okay(self):
|
|
stack_name = 'srv_val'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
tmpl.t['Resources']['WebServer']['Properties']['personality'] = \
|
|
{"/fake/path1": "a" * 10240}
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('server_create_image_err',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
self.m.StubOutWithMock(self.fc.limits, 'get')
|
|
self.fc.limits.get().MultipleTimes().AndReturn(self.limits)
|
|
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', 'image_id')
|
|
self.m.ReplayAll()
|
|
|
|
self.assertIsNone(server.validate())
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_validate_personality_file_size_too_big(self):
|
|
stack_name = 'srv_val'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
tmpl.t['Resources']['WebServer']['Properties']['personality'] = \
|
|
{"/fake/path1": "a" * 10241}
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('server_create_image_err',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
self.m.StubOutWithMock(self.fc.limits, 'get')
|
|
self.fc.limits.get().MultipleTimes().AndReturn(self.limits)
|
|
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', 'image_id')
|
|
self.m.ReplayAll()
|
|
|
|
exc = self.assertRaises(exception.StackValidationFailed,
|
|
server.validate)
|
|
self.assertEqual("The contents of personality file \"/fake/path1\" "
|
|
"is larger than the maximum allowed personality "
|
|
"file size (10240 bytes).", six.text_type(exc))
|
|
self.m.VerifyAll()
|
|
|
|
def test_resolve_attribute_server_not_found(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._create_test_server(return_server,
|
|
'srv_resolve_attr')
|
|
|
|
server.resource_id = '1234'
|
|
self.m.StubOutWithMock(self.fc.client, 'get_servers_1234')
|
|
get = self.fc.client.get_servers_1234
|
|
get().AndRaise(fakes_v1_1.fake_exception())
|
|
mox.Replay(get)
|
|
self.m.ReplayAll()
|
|
|
|
self.assertEqual(server._resolve_attribute("accessIPv4"), '')
|
|
self.m.VerifyAll()
|
|
|
|
def test_default_instance_user(self):
|
|
"""The default value for instance_user in heat.conf is ec2-user."""
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._setup_test_server(return_server, 'default_user')
|
|
self.m.StubOutWithMock(nova_utils, 'build_userdata')
|
|
nova_utils.build_userdata(server,
|
|
'wordpress',
|
|
instance_user='ec2-user',
|
|
user_data_format='HEAT_CFNTOOLS')
|
|
self.m.ReplayAll()
|
|
scheduler.TaskRunner(server.create)()
|
|
self.m.VerifyAll()
|
|
|
|
def test_admin_user_property(self):
|
|
"""Test the admin_user property on the server overrides instance_user.
|
|
|
|
Launching the instance should call build_userdata with the
|
|
custom user name. This property is deprecated and will be
|
|
removed in Juno.
|
|
"""
|
|
return_server = self.fc.servers.list()[1]
|
|
stack_name = 'stack_with_custom_admin_user_server'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
wsp = tmpl.t['Resources']['WebServer']['Properties']
|
|
wsp['admin_user'] = 'custom_user'
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('create_metadata_test_server',
|
|
resource_defns['WebServer'], stack)
|
|
self.m.StubOutWithMock(self.fc.servers, 'create')
|
|
image_id = mox.IgnoreArg()
|
|
self.fc.servers.create(
|
|
image=image_id, flavor=mox.IgnoreArg(), key_name='test',
|
|
name=mox.IgnoreArg(), security_groups=[],
|
|
userdata=mox.IgnoreArg(), scheduler_hints=None,
|
|
meta=mox.IgnoreArg(), nics=None, availability_zone=None,
|
|
block_device_mapping=None, config_drive=None,
|
|
disk_config=None, reservation_id=None, files={},
|
|
admin_pass=None).AndReturn(return_server)
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', image_id)
|
|
self.m.StubOutWithMock(nova_utils, 'build_userdata')
|
|
nova_utils.build_userdata(server,
|
|
'wordpress',
|
|
instance_user='custom_user',
|
|
user_data_format='HEAT_CFNTOOLS')
|
|
self.m.ReplayAll()
|
|
scheduler.TaskRunner(server.create)()
|
|
self.m.VerifyAll()
|
|
|
|
def test_custom_instance_user(self):
|
|
"""Test instance_user in heat.conf being set to a custom value.
|
|
|
|
Launching the instance should call build_userdata with the
|
|
custom user name.
|
|
|
|
This option is deprecated and will be removed in Juno.
|
|
"""
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._setup_test_server(return_server, 'custom_user')
|
|
self.m.StubOutWithMock(servers.cfg.CONF, 'instance_user')
|
|
servers.cfg.CONF.instance_user = 'custom_user'
|
|
self.m.StubOutWithMock(nova_utils, 'build_userdata')
|
|
nova_utils.build_userdata(server,
|
|
'wordpress',
|
|
instance_user='custom_user',
|
|
user_data_format='HEAT_CFNTOOLS')
|
|
self.m.ReplayAll()
|
|
scheduler.TaskRunner(server.create)()
|
|
self.m.VerifyAll()
|
|
|
|
def test_empty_instance_user(self):
|
|
"""Test instance_user in heat.conf being empty.
|
|
|
|
Launching the instance should not pass any user to
|
|
build_userdata. The default cloud-init user set up for the image
|
|
will be used instead.
|
|
|
|
This will the default behaviour in Juno once we remove the
|
|
instance_user option.
|
|
"""
|
|
return_server = self.fc.servers.list()[1]
|
|
server = self._setup_test_server(return_server, 'custom_user')
|
|
self.m.StubOutWithMock(servers.cfg.CONF, 'instance_user')
|
|
servers.cfg.CONF.instance_user = ''
|
|
self.m.StubOutWithMock(nova_utils, 'build_userdata')
|
|
nova_utils.build_userdata(server,
|
|
'wordpress',
|
|
instance_user=None,
|
|
user_data_format='HEAT_CFNTOOLS')
|
|
self.m.ReplayAll()
|
|
scheduler.TaskRunner(server.create)()
|
|
self.m.VerifyAll()
|
|
|
|
def create_old_net(self, port=None, net=None, ip=None):
|
|
return {'port': port, 'network': net, 'fixed_ip': ip, 'uuid': None}
|
|
|
|
def create_fake_iface(self, port, net, ip):
|
|
class fake_interface():
|
|
def __init__(self, port_id, net_id, fixed_ip):
|
|
self.port_id = port_id
|
|
self.net_id = net_id
|
|
self.fixed_ips = [{'ip_address': fixed_ip}]
|
|
|
|
return fake_interface(port, net, ip)
|
|
|
|
def test_get_network_matches_no_matching(self):
|
|
return_server = self.fc.servers.list()[3]
|
|
server = self._create_test_server(return_server, 'networks_update')
|
|
|
|
for new_nets in ([],
|
|
[{'port': '952fd4ae-53b9-4b39-9e5f-8929c553b5ae'}]):
|
|
|
|
old_nets = [
|
|
self.create_old_net(
|
|
port='2a60cbaa-3d33-4af6-a9ce-83594ac546fc'),
|
|
self.create_old_net(
|
|
net='f3ef5d2f-d7ba-4b27-af66-58ca0b81e032', ip='1.2.3.4'),
|
|
self.create_old_net(
|
|
net='0da8adbf-a7e2-4c59-a511-96b03d2da0d7')]
|
|
|
|
new_nets_copy = copy.deepcopy(new_nets)
|
|
old_nets_copy = copy.deepcopy(old_nets)
|
|
for net in new_nets_copy:
|
|
for key in ('port', 'network', 'fixed_ip', 'uuid'):
|
|
net.setdefault(key)
|
|
|
|
matched_nets = server._get_network_matches(old_nets, new_nets)
|
|
self.assertEqual([], matched_nets)
|
|
self.assertEqual(old_nets_copy, old_nets)
|
|
self.assertEqual(new_nets_copy, new_nets)
|
|
|
|
def test_get_network_matches_success(self):
|
|
return_server = self.fc.servers.list()[3]
|
|
server = self._create_test_server(return_server, 'networks_update')
|
|
|
|
old_nets = [
|
|
self.create_old_net(
|
|
port='2a60cbaa-3d33-4af6-a9ce-83594ac546fc'),
|
|
self.create_old_net(
|
|
net='f3ef5d2f-d7ba-4b27-af66-58ca0b81e032',
|
|
ip='1.2.3.4'),
|
|
self.create_old_net(
|
|
net='0da8adbf-a7e2-4c59-a511-96b03d2da0d7')]
|
|
new_nets = [
|
|
{'port': '2a60cbaa-3d33-4af6-a9ce-83594ac546fc'},
|
|
{'network': 'f3ef5d2f-d7ba-4b27-af66-58ca0b81e032',
|
|
'fixed_ip': '1.2.3.4'},
|
|
{'port': '952fd4ae-53b9-4b39-9e5f-8929c553b5ae'}]
|
|
|
|
new_nets_copy = copy.deepcopy(new_nets)
|
|
old_nets_copy = copy.deepcopy(old_nets)
|
|
for net in new_nets_copy:
|
|
for key in ('port', 'network', 'fixed_ip', 'uuid'):
|
|
net.setdefault(key)
|
|
|
|
matched_nets = server._get_network_matches(old_nets, new_nets)
|
|
self.assertEqual(old_nets_copy[:-1], matched_nets)
|
|
self.assertEqual([old_nets_copy[2]], old_nets)
|
|
self.assertEqual([new_nets_copy[2]], new_nets)
|
|
|
|
def test_update_networks_matching_iface_port(self):
|
|
return_server = self.fc.servers.list()[3]
|
|
server = self._create_test_server(return_server, 'networks_update')
|
|
|
|
# old order 0 1 2 3 4 5
|
|
nets = [
|
|
{'port': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'network': None, 'fixed_ip': None},
|
|
{'port': None, 'network': 'gggggggg-1111-1111-1111-gggggggggggg',
|
|
'fixed_ip': '1.2.3.4', },
|
|
{'port': None, 'network': 'f3ef5d2f-d7ba-4b27-af66-58ca0b81e032',
|
|
'fixed_ip': None},
|
|
{'port': 'dddddddd-dddd-dddd-dddd-dddddddddddd',
|
|
'network': None, 'fixed_ip': None},
|
|
{'port': None, 'network': 'gggggggg-1111-1111-1111-gggggggggggg',
|
|
'fixed_ip': '5.6.7.8'},
|
|
{'port': None, 'network': '0da8adbf-a7e2-4c59-a511-96b03d2da0d7',
|
|
'fixed_ip': None}]
|
|
# new order 5 2 3 0 1 4
|
|
interfaces = [
|
|
self.create_fake_iface('ffffffff-ffff-ffff-ffff-ffffffffffff',
|
|
nets[5]['network'], '10.0.0.10'),
|
|
self.create_fake_iface('cccccccc-cccc-cccc-cccc-cccccccccccc',
|
|
nets[2]['network'], '10.0.0.11'),
|
|
self.create_fake_iface(nets[3]['port'],
|
|
'f3ef5d2f-d7ba-4b27-af66-58ca0b81e032',
|
|
'10.0.0.12'),
|
|
self.create_fake_iface(nets[0]['port'],
|
|
'gggggggg-1111-1111-1111-gggggggggggg',
|
|
'10.0.0.13'),
|
|
self.create_fake_iface('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb',
|
|
nets[1]['network'], nets[1]['fixed_ip']),
|
|
self.create_fake_iface('eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee',
|
|
nets[4]['network'], nets[4]['fixed_ip'])]
|
|
# all networks should get port id
|
|
expected = [
|
|
{'port': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'network': None, 'fixed_ip': None},
|
|
{'port': 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb',
|
|
'network': 'gggggggg-1111-1111-1111-gggggggggggg',
|
|
'fixed_ip': '1.2.3.4'},
|
|
{'port': 'cccccccc-cccc-cccc-cccc-cccccccccccc',
|
|
'network': 'f3ef5d2f-d7ba-4b27-af66-58ca0b81e032',
|
|
'fixed_ip': None},
|
|
{'port': 'dddddddd-dddd-dddd-dddd-dddddddddddd',
|
|
'network': None, 'fixed_ip': None},
|
|
{'port': 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee',
|
|
'network': 'gggggggg-1111-1111-1111-gggggggggggg',
|
|
'fixed_ip': '5.6.7.8'},
|
|
{'port': 'ffffffff-ffff-ffff-ffff-ffffffffffff',
|
|
'network': '0da8adbf-a7e2-4c59-a511-96b03d2da0d7',
|
|
'fixed_ip': None}]
|
|
|
|
server.update_networks_matching_iface_port(nets, interfaces)
|
|
self.assertEqual(expected, nets)
|
|
|
|
def test_server_update_None_networks_with_port(self):
|
|
return_server = self.fc.servers.list()[3]
|
|
return_server.id = '9102'
|
|
server = self._create_test_server(return_server, 'networks_update')
|
|
|
|
new_networks = [{'port': '2a60cbaa-3d33-4af6-a9ce-83594ac546fc'}]
|
|
update_template = copy.deepcopy(server.t)
|
|
update_template['Properties']['networks'] = new_networks
|
|
|
|
self.m.StubOutWithMock(self.fc.servers, 'get')
|
|
self.fc.servers.get('9102').MultipleTimes().AndReturn(return_server)
|
|
# to make sure, that old_networks will be None
|
|
self.assertFalse(hasattr(server.t['Properties'], 'networks'))
|
|
|
|
iface = self.create_fake_iface('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'450abbc9-9b6d-4d6f-8c3a-c47ac34100ef',
|
|
'1.2.3.4')
|
|
self.m.StubOutWithMock(return_server, 'interface_list')
|
|
return_server.interface_list().AndReturn([iface])
|
|
|
|
self.m.StubOutWithMock(return_server, 'interface_detach')
|
|
return_server.interface_detach(
|
|
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa').AndReturn(None)
|
|
|
|
self.m.StubOutWithMock(return_server, 'interface_attach')
|
|
return_server.interface_attach(new_networks[0]['port'],
|
|
None, None).AndReturn(None)
|
|
self.m.ReplayAll()
|
|
|
|
scheduler.TaskRunner(server.update, update_template)()
|
|
self.assertEqual((server.UPDATE, server.COMPLETE), server.state)
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_update_None_networks_with_network_id(self):
|
|
return_server = self.fc.servers.list()[3]
|
|
return_server.id = '9102'
|
|
server = self._create_test_server(return_server, 'networks_update')
|
|
|
|
new_networks = [{'network': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'fixed_ip': '1.2.3.4'}]
|
|
update_template = copy.deepcopy(server.t)
|
|
update_template['Properties']['networks'] = new_networks
|
|
|
|
self.m.StubOutWithMock(self.fc.servers, 'get')
|
|
self.fc.servers.get('9102').MultipleTimes().AndReturn(return_server)
|
|
# to make sure, that old_networks will be None
|
|
self.assertFalse(hasattr(server.t['Properties'], 'networks'))
|
|
|
|
iface = self.create_fake_iface('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'450abbc9-9b6d-4d6f-8c3a-c47ac34100ef',
|
|
'1.2.3.4')
|
|
self.m.StubOutWithMock(return_server, 'interface_list')
|
|
return_server.interface_list().AndReturn([iface])
|
|
|
|
self.m.StubOutWithMock(return_server, 'interface_detach')
|
|
return_server.interface_detach(
|
|
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa').AndReturn(None)
|
|
|
|
self.m.StubOutWithMock(return_server, 'interface_attach')
|
|
return_server.interface_attach(None, new_networks[0]['network'],
|
|
new_networks[0]['fixed_ip']).AndReturn(
|
|
None)
|
|
self.m.ReplayAll()
|
|
|
|
scheduler.TaskRunner(server.update, update_template)()
|
|
self.assertEqual((server.UPDATE, server.COMPLETE), server.state)
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_update_empty_networks_with_complex_parameters(self):
|
|
return_server = self.fc.servers.list()[3]
|
|
return_server.id = '9102'
|
|
server = self._create_test_server(return_server, 'networks_update')
|
|
|
|
new_networks = [{'network': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'fixed_ip': '1.2.3.4',
|
|
'port': '2a60cbaa-3d33-4af6-a9ce-83594ac546fc'}]
|
|
update_template = copy.deepcopy(server.t)
|
|
update_template['Properties']['networks'] = new_networks
|
|
|
|
self.m.StubOutWithMock(self.fc.servers, 'get')
|
|
self.fc.servers.get('9102').MultipleTimes().AndReturn(return_server)
|
|
# to make sure, that old_networks will be None
|
|
self.assertFalse(hasattr(server.t['Properties'], 'networks'))
|
|
|
|
iface = self.create_fake_iface('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'450abbc9-9b6d-4d6f-8c3a-c47ac34100ef',
|
|
'1.2.3.4')
|
|
self.m.StubOutWithMock(return_server, 'interface_list')
|
|
return_server.interface_list().AndReturn([iface])
|
|
|
|
self.m.StubOutWithMock(return_server, 'interface_detach')
|
|
return_server.interface_detach(
|
|
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa').AndReturn(None)
|
|
|
|
self.m.StubOutWithMock(return_server, 'interface_attach')
|
|
return_server.interface_attach(
|
|
new_networks[0]['port'], None, None).AndReturn(None)
|
|
|
|
self.m.ReplayAll()
|
|
|
|
scheduler.TaskRunner(server.update, update_template)()
|
|
self.assertEqual((server.UPDATE, server.COMPLETE), server.state)
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_update_networks_with_complex_parameters(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
return_server.id = '5678'
|
|
server = self._create_test_server(return_server, 'networks_update')
|
|
|
|
old_networks = [
|
|
{'port': '95e25541-d26a-478d-8f36-ae1c8f6b74dc'},
|
|
{'network': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'fixed_ip': '1.2.3.4'},
|
|
{'port': '4121f61a-1b2e-4ab0-901e-eade9b1cb09d'},
|
|
{'network': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'fixed_ip': '31.32.33.34'}]
|
|
|
|
new_networks = [
|
|
{'network': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'fixed_ip': '1.2.3.4'},
|
|
{'port': '2a60cbaa-3d33-4af6-a9ce-83594ac546fc'}]
|
|
|
|
server.t['Properties']['networks'] = old_networks
|
|
update_template = copy.deepcopy(server.t)
|
|
update_template['Properties']['networks'] = new_networks
|
|
|
|
self.m.StubOutWithMock(self.fc.servers, 'get')
|
|
self.fc.servers.get('5678').MultipleTimes().AndReturn(return_server)
|
|
|
|
self.m.StubOutWithMock(return_server, 'interface_list')
|
|
|
|
poor_interfaces = [
|
|
self.create_fake_iface('95e25541-d26a-478d-8f36-ae1c8f6b74dc',
|
|
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'11.12.13.14'),
|
|
self.create_fake_iface('450abbc9-9b6d-4d6f-8c3a-c47ac34100ef',
|
|
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'1.2.3.4'),
|
|
self.create_fake_iface('4121f61a-1b2e-4ab0-901e-eade9b1cb09d',
|
|
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'21.22.23.24'),
|
|
self.create_fake_iface('0907fa82-a024-43c2-9fc5-efa1bccaa74a',
|
|
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'31.32.33.34')
|
|
]
|
|
|
|
return_server.interface_list().AndReturn(poor_interfaces)
|
|
|
|
self.m.StubOutWithMock(return_server, 'interface_detach')
|
|
return_server.interface_detach(
|
|
poor_interfaces[0].port_id).InAnyOrder().AndReturn(None)
|
|
return_server.interface_detach(
|
|
poor_interfaces[2].port_id).InAnyOrder().AndReturn(None)
|
|
return_server.interface_detach(
|
|
poor_interfaces[3].port_id).InAnyOrder().AndReturn(None)
|
|
|
|
self.m.StubOutWithMock(return_server, 'interface_attach')
|
|
return_server.interface_attach(
|
|
new_networks[1]['port'], None, None).AndReturn(None)
|
|
self.m.ReplayAll()
|
|
|
|
scheduler.TaskRunner(server.update, update_template)()
|
|
self.assertEqual((server.UPDATE, server.COMPLETE), server.state)
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_update_networks_with_None(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
return_server.id = '5678'
|
|
server = self._create_test_server(return_server, 'networks_update')
|
|
|
|
old_networks = [
|
|
{'port': '95e25541-d26a-478d-8f36-ae1c8f6b74dc'},
|
|
{'port': '4121f61a-1b2e-4ab0-901e-eade9b1cb09d'},
|
|
{'network': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'fixed_ip': '31.32.33.34'}]
|
|
|
|
server.t['Properties']['networks'] = old_networks
|
|
update_template = copy.deepcopy(server.t)
|
|
update_template['Properties']['networks'] = None
|
|
|
|
self.m.StubOutWithMock(self.fc.servers, 'get')
|
|
self.fc.servers.get('5678').MultipleTimes().AndReturn(return_server)
|
|
|
|
self.m.StubOutWithMock(return_server, 'interface_list')
|
|
|
|
poor_interfaces = [
|
|
self.create_fake_iface('95e25541-d26a-478d-8f36-ae1c8f6b74dc',
|
|
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'11.12.13.14'),
|
|
self.create_fake_iface('4121f61a-1b2e-4ab0-901e-eade9b1cb09d',
|
|
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'21.22.23.24'),
|
|
self.create_fake_iface('0907fa82-a024-43c2-9fc5-efa1bccaa74a',
|
|
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'31.32.33.34')
|
|
]
|
|
|
|
return_server.interface_list().AndReturn(poor_interfaces)
|
|
|
|
self.m.StubOutWithMock(return_server, 'interface_detach')
|
|
return_server.interface_detach(
|
|
poor_interfaces[0].port_id).InAnyOrder().AndReturn(None)
|
|
return_server.interface_detach(
|
|
poor_interfaces[1].port_id).InAnyOrder().AndReturn(None)
|
|
return_server.interface_detach(
|
|
poor_interfaces[2].port_id).InAnyOrder().AndReturn(None)
|
|
|
|
self.m.StubOutWithMock(return_server, 'interface_attach')
|
|
return_server.interface_attach(None, None, None).AndReturn(None)
|
|
self.m.ReplayAll()
|
|
|
|
scheduler.TaskRunner(server.update, update_template)()
|
|
self.assertEqual((server.UPDATE, server.COMPLETE), server.state)
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_update_networks_with_empty_list(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
return_server.id = '5678'
|
|
server = self._create_test_server(return_server, 'networks_update')
|
|
|
|
old_networks = [
|
|
{'port': '95e25541-d26a-478d-8f36-ae1c8f6b74dc'},
|
|
{'port': '4121f61a-1b2e-4ab0-901e-eade9b1cb09d'},
|
|
{'network': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'fixed_ip': '31.32.33.34'}]
|
|
|
|
server.t['Properties']['networks'] = old_networks
|
|
update_template = copy.deepcopy(server.t)
|
|
update_template['Properties']['networks'] = []
|
|
|
|
self.m.StubOutWithMock(self.fc.servers, 'get')
|
|
self.fc.servers.get('5678').MultipleTimes().AndReturn(return_server)
|
|
|
|
self.m.StubOutWithMock(return_server, 'interface_list')
|
|
|
|
poor_interfaces = [
|
|
self.create_fake_iface('95e25541-d26a-478d-8f36-ae1c8f6b74dc',
|
|
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'11.12.13.14'),
|
|
self.create_fake_iface('4121f61a-1b2e-4ab0-901e-eade9b1cb09d',
|
|
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'21.22.23.24'),
|
|
self.create_fake_iface('0907fa82-a024-43c2-9fc5-efa1bccaa74a',
|
|
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
|
'31.32.33.34')
|
|
]
|
|
|
|
return_server.interface_list().AndReturn(poor_interfaces)
|
|
|
|
self.m.StubOutWithMock(return_server, 'interface_detach')
|
|
return_server.interface_detach(
|
|
poor_interfaces[0].port_id).InAnyOrder().AndReturn(None)
|
|
return_server.interface_detach(
|
|
poor_interfaces[1].port_id).InAnyOrder().AndReturn(None)
|
|
return_server.interface_detach(
|
|
poor_interfaces[2].port_id).InAnyOrder().AndReturn(None)
|
|
|
|
self.m.StubOutWithMock(return_server, 'interface_attach')
|
|
return_server.interface_attach(None, None, None).AndReturn(None)
|
|
self.m.ReplayAll()
|
|
|
|
scheduler.TaskRunner(server.update, update_template)()
|
|
self.assertEqual((server.UPDATE, server.COMPLETE), server.state)
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_properties_validation_create_and_update(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
|
|
self.m.StubOutWithMock(glance.ImageConstraint, "validate")
|
|
# verify that validate gets invoked exactly once for create
|
|
glance.ImageConstraint.validate(
|
|
'CentOS 5.2', mox.IgnoreArg()).AndReturn(True)
|
|
# verify that validate gets invoked exactly once for update
|
|
glance.ImageConstraint.validate(
|
|
'Update Image', mox.IgnoreArg()).AndReturn(True)
|
|
self.m.ReplayAll()
|
|
|
|
# create
|
|
server = self._create_test_server(return_server,
|
|
'my_server')
|
|
|
|
update_template = copy.deepcopy(server.t)
|
|
update_template['Properties']['image'] = 'Update Image'
|
|
|
|
#update
|
|
updater = scheduler.TaskRunner(server.update, update_template)
|
|
self.assertRaises(resource.UpdateReplace, updater)
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_properties_validation_create_and_update_fail(self):
|
|
return_server = self.fc.servers.list()[1]
|
|
|
|
self.m.StubOutWithMock(glance.ImageConstraint, "validate")
|
|
# verify that validate gets invoked exactly once for create
|
|
glance.ImageConstraint.validate(
|
|
'CentOS 5.2', mox.IgnoreArg()).AndReturn(True)
|
|
# verify that validate gets invoked exactly once for update
|
|
ex = exception.ImageNotFound(image_name='Update Image')
|
|
glance.ImageConstraint.validate('Update Image',
|
|
mox.IgnoreArg()).AndRaise(ex)
|
|
self.m.ReplayAll()
|
|
|
|
# create
|
|
server = self._create_test_server(return_server,
|
|
'my_server')
|
|
|
|
update_template = copy.deepcopy(server.t)
|
|
update_template['Properties']['image'] = 'Update Image'
|
|
|
|
#update
|
|
updater = scheduler.TaskRunner(server.update, update_template)
|
|
err = self.assertRaises(exception.ResourceFailure, updater)
|
|
self.assertEqual('StackValidationFailed: Property error : WebServer: '
|
|
'image The Image (Update Image) could not be found.',
|
|
six.text_type(err))
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_server_dont_validate_personality_if_personality_isnt_set(self):
|
|
stack_name = 'srv_val'
|
|
(tmpl, stack) = self._setup_test_stack(stack_name)
|
|
|
|
resource_defns = tmpl.resource_definitions(stack)
|
|
server = servers.Server('server_create_image_err',
|
|
resource_defns['WebServer'], stack)
|
|
|
|
# We mock out nova_utils.absolute_limits but we don't specify
|
|
# how this mock should behave, so mox will verify that this mock
|
|
# is NOT called during call to server.validate().
|
|
# This is the way to validate that no excessive calls to Nova
|
|
# are made during validation.
|
|
self.m.StubOutWithMock(nova_utils, 'absolute_limits')
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', 'image_id')
|
|
self.m.ReplayAll()
|
|
|
|
# Assert here checks that server resource validates, but actually
|
|
# this call is Act stage of this test. We calling server.validate()
|
|
# to verify that no excessive calls to Nova are made during validation.
|
|
self.assertIsNone(server.validate())
|
|
self.m.VerifyAll()
|
|
|
|
|
|
class FlavorConstraintTest(HeatTestCase):
|
|
|
|
def test_validate(self):
|
|
client = fakes.FakeClient()
|
|
self.stub_keystoneclient()
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(client)
|
|
client.flavors = self.m.CreateMockAnything()
|
|
|
|
flavor = collections.namedtuple("Flavor", ["id", "name"])
|
|
flavor.id = "1234"
|
|
flavor.name = "foo"
|
|
client.flavors.list().MultipleTimes().AndReturn([flavor])
|
|
self.m.ReplayAll()
|
|
|
|
constraint = servers.FlavorConstraint()
|
|
ctx = utils.dummy_context()
|
|
self.assertFalse(constraint.validate("bar", ctx))
|
|
self.assertTrue(constraint.validate("foo", ctx))
|
|
self.assertTrue(constraint.validate("1234", ctx))
|
|
|
|
self.m.VerifyAll()
|