shaker/shaker/tests/test_deploy.py

1153 lines
44 KiB
Python

# Copyright (c) 2015 Mirantis Inc.
#
# 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 itertools
import mock
import os
import re
import testtools
import uuid
from oslo_config import cfg
from oslo_config import fixture as config_fixture_pkg
from shaker.engine import config
from shaker.engine import deploy
from shaker.engine import utils
from shaker.openstack.clients import heat
from shaker.openstack.clients import nova
from shaker.tests import fakes
from timeout_decorator import TimeoutError
ZONE = 'zone'
def nodes_helper(*nodes):
return [dict(host=n, zone=ZONE) for n in nodes]
class TestDeploy(testtools.TestCase):
def setUp(self):
super(TestDeploy, self).setUp()
conf = cfg.CONF
self.addCleanup(conf.reset)
self.config_fixture = self.useFixture(config_fixture_pkg.Config(conf))
conf.register_opts(
config.COMMON_OPTS + config.OPENSTACK_OPTS + config.SERVER_OPTS +
config.REPORT_OPTS)
def test_generate_agents_alone_single_room(self):
unique = 'UU1D'
expected = {
'UU1D_agent_0': {
'id': 'UU1D_agent_0',
'mode': 'alone',
'availability_zone': '%s:uno' % ZONE,
'zone': ZONE,
'node': 'uno'},
'UU1D_agent_1': {
'id': 'UU1D_agent_1',
'mode': 'alone',
'availability_zone': '%s:dos' % ZONE,
'zone': ZONE,
'node': 'dos'},
}
accommodation = deploy.normalize_accommodation(['single_room'])
actual = deploy.generate_agents(nodes_helper('uno', 'dos'),
accommodation,
unique)
self.assertEqual(expected, actual)
def test_generate_agents_alone_single_room_az_host(self):
unique = 'UU1D'
expected = {
'UU1D_agent_0': {
'id': 'UU1D_agent_0',
'mode': 'alone',
'availability_zone': '%s:uno' % ZONE,
'zone': ZONE,
'node': 'uno'},
}
zones = ['%s:uno' % ZONE]
accommodation = deploy.normalize_accommodation(
['single_room', {'zones': zones}])
actual = deploy.generate_agents(nodes_helper('uno', 'dos'),
accommodation,
unique)
self.assertEqual(expected, actual)
def test_generate_agents_pair_single_room(self):
unique = 'UU1D'
expected = {
'UU1D_master_0': {
'id': 'UU1D_master_0',
'mode': 'master',
'availability_zone': '%s:uno' % ZONE,
'node': 'uno',
'zone': ZONE,
'slave_id': 'UU1D_slave_0'},
'UU1D_slave_0': {
'id': 'UU1D_slave_0',
'master_id': 'UU1D_master_0',
'mode': 'slave',
'availability_zone': '%s:dos' % ZONE,
'zone': ZONE,
'node': 'dos'},
}
accommodation = deploy.normalize_accommodation(['pair', 'single_room'])
actual = deploy.generate_agents(nodes_helper('uno', 'dos', 'tre'),
accommodation,
unique)
self.assertEqual(expected, actual)
def test_generate_agents_pair_single_room_az_host(self):
unique = 'UU1D'
expected = {
'UU1D_master_0': {
'id': 'UU1D_master_0',
'mode': 'master',
'availability_zone': '%s:uno' % ZONE,
'node': 'uno',
'zone': ZONE,
'slave_id': 'UU1D_slave_0'},
'UU1D_slave_0': {
'id': 'UU1D_slave_0',
'master_id': 'UU1D_master_0',
'mode': 'slave',
'availability_zone': '%s:dos' % ZONE,
'zone': ZONE,
'node': 'dos'},
}
zones = ['%s:uno' % ZONE, '%s:dos' % ZONE]
accommodation = deploy.normalize_accommodation(
['pair', 'single_room', {'zones': zones}])
actual = deploy.generate_agents(nodes_helper('uno', 'dos', 'tre'),
accommodation,
unique)
self.assertEqual(expected, actual)
def test_generate_agents_pair_single_room_not_enough(self):
unique = 'UU1D'
accommodation = deploy.normalize_accommodation(['pair', 'single_room'])
self.assertRaises(deploy.DeploymentException, deploy.generate_agents,
['uno'], accommodation, unique)
def test_generate_agents_pair_single_room_compute_nodes_not_enough(self):
unique = 'UU1D'
accommodation = deploy.normalize_accommodation(
['pair', 'single_room', {'compute_nodes': 2}])
self.assertRaises(deploy.DeploymentException, deploy.generate_agents,
['uno'], accommodation, unique)
def test_generate_agents_pair_double_room(self):
unique = 'UU1D'
expected = {
'UU1D_master_0': {
'id': 'UU1D_master_0',
'mode': 'master',
'availability_zone': '%s:uno' % ZONE,
'node': 'uno',
'zone': ZONE,
'slave_id': 'UU1D_slave_0'},
'UU1D_slave_0': {
'id': 'UU1D_slave_0',
'master_id': 'UU1D_master_0',
'mode': 'slave',
'availability_zone': '%s:uno' % ZONE,
'zone': ZONE,
'node': 'uno'},
'UU1D_master_1': {
'id': 'UU1D_master_1',
'mode': 'master',
'availability_zone': '%s:dos' % ZONE,
'node': 'dos',
'zone': ZONE,
'slave_id': 'UU1D_slave_1'},
'UU1D_slave_1': {
'id': 'UU1D_slave_1',
'master_id': 'UU1D_master_1',
'mode': 'slave',
'availability_zone': '%s:dos' % ZONE,
'zone': ZONE,
'node': 'dos'},
'UU1D_master_2': {
'id': 'UU1D_master_2',
'mode': 'master',
'availability_zone': '%s:tre' % ZONE,
'node': 'tre',
'zone': ZONE,
'slave_id': 'UU1D_slave_2'},
'UU1D_slave_2': {
'id': 'UU1D_slave_2',
'master_id': 'UU1D_master_2',
'mode': 'slave',
'availability_zone': '%s:tre' % ZONE,
'zone': ZONE,
'node': 'tre'},
}
accommodation = deploy.normalize_accommodation(['pair', 'double_room'])
actual = deploy.generate_agents(nodes_helper('uno', 'dos', 'tre'),
accommodation,
unique)
self.assertEqual(expected, actual)
def test_generate_agents_pair_double_room_az_host(self):
unique = 'UU1D'
expected = {
'UU1D_master_0': {
'id': 'UU1D_master_0',
'mode': 'master',
'availability_zone': '%s:uno' % ZONE,
'node': 'uno',
'zone': ZONE,
'slave_id': 'UU1D_slave_0'},
'UU1D_slave_0': {
'id': 'UU1D_slave_0',
'master_id': 'UU1D_master_0',
'mode': 'slave',
'availability_zone': '%s:uno' % ZONE,
'zone': ZONE,
'node': 'uno'},
'UU1D_master_1': {
'id': 'UU1D_master_1',
'mode': 'master',
'availability_zone': '%s:dos' % ZONE,
'node': 'dos',
'zone': ZONE,
'slave_id': 'UU1D_slave_1'},
'UU1D_slave_1': {
'id': 'UU1D_slave_1',
'master_id': 'UU1D_master_1',
'mode': 'slave',
'availability_zone': '%s:dos' % ZONE,
'zone': ZONE,
'node': 'dos'},
}
zones = ['%s:uno' % ZONE, '%s:dos' % ZONE]
accommodation = deploy.normalize_accommodation(
['pair', 'double_room', {'zones': zones}])
actual = deploy.generate_agents(nodes_helper('uno', 'dos', 'tre'),
accommodation,
unique)
self.assertEqual(expected, actual)
def test_generate_agents_pair_mixed_room(self):
unique = 'UU1D'
expected = {
'UU1D_master_0': {
'id': 'UU1D_master_0',
'mode': 'master',
'availability_zone': '%s:uno' % ZONE,
'zone': ZONE,
'node': 'uno',
'slave_id': 'UU1D_slave_0'},
'UU1D_slave_0': {
'id': 'UU1D_slave_0',
'master_id': 'UU1D_master_0',
'mode': 'slave',
'availability_zone': '%s:dos' % ZONE,
'zone': ZONE,
'node': 'dos'},
'UU1D_master_1': {
'id': 'UU1D_master_1',
'mode': 'master',
'availability_zone': '%s:dos' % ZONE,
'zone': ZONE,
'node': 'dos',
'slave_id': 'UU1D_slave_1'},
'UU1D_slave_1': {
'id': 'UU1D_slave_1',
'master_id': 'UU1D_master_1',
'mode': 'slave',
'availability_zone': '%s:uno' % ZONE,
'zone': ZONE,
'node': 'uno'},
}
accommodation = deploy.normalize_accommodation(['pair', 'mixed_room'])
actual = deploy.generate_agents(nodes_helper('uno', 'dos'),
accommodation,
unique)
self.assertEqual(expected, actual)
def test_generate_agents_alone_single_room_double_density(self):
unique = 'UU1D'
expected = {
'UU1D_agent_0': {
'id': 'UU1D_agent_0',
'mode': 'alone',
'availability_zone': '%s:uno' % ZONE,
'zone': ZONE,
'node': 'uno'},
'UU1D_agent_1': {
'id': 'UU1D_agent_1',
'mode': 'alone',
'availability_zone': '%s:uno' % ZONE,
'zone': ZONE,
'node': 'uno'},
}
accommodation = deploy.normalize_accommodation(
['single_room', {'density': 2}])
actual = deploy.generate_agents(nodes_helper('uno'),
accommodation,
unique)
self.assertEqual(expected, actual)
@mock.patch('random.sample')
def test_generate_agents_alone_single_room_compute_nodes(self, mr):
unique = 'UU1D'
expected = {
'UU1D_agent_0': {
'id': 'UU1D_agent_0',
'mode': 'alone',
'availability_zone': '%s:uno' % ZONE,
'zone': ZONE,
'node': 'uno'},
'UU1D_agent_1': {
'id': 'UU1D_agent_1',
'mode': 'alone',
'availability_zone': '%s:duo' % ZONE,
'zone': ZONE,
'node': 'duo'},
}
compute_nodes = nodes_helper('uno', 'duo', 'tre')
mr.side_effect = lambda x, n: x[:n]
accommodation = deploy.normalize_accommodation(
['single_room', {'compute_nodes': 2}])
actual = deploy.generate_agents(compute_nodes,
accommodation,
unique)
self.assertEqual(expected, actual)
@mock.patch('random.sample')
def test_generate_agents_alone_single_room_density_compute_nodes(self, mr):
unique = 'UU1D'
expected = {
'UU1D_agent_0': {
'id': 'UU1D_agent_0',
'mode': 'alone',
'availability_zone': '%s:uno' % ZONE,
'zone': ZONE,
'node': 'uno'},
'UU1D_agent_1': {
'id': 'UU1D_agent_1',
'mode': 'alone',
'availability_zone': '%s:uno' % ZONE,
'zone': ZONE,
'node': 'uno'},
}
compute_nodes = nodes_helper('uno', 'duo', 'tre')
mr.side_effect = lambda x, n: x[:n]
accommodation = deploy.normalize_accommodation(
['single_room', {'compute_nodes': 1}, {'density': 2}])
actual = deploy.generate_agents(compute_nodes,
accommodation,
unique)
self.assertEqual(expected, actual)
@mock.patch('random.sample')
def test_generate_agents_pair_single_room_density_compute_nodes(self, mr):
unique = 'UU1D'
compute_nodes = nodes_helper('uno', 'duo', 'tre')
mr.side_effect = lambda x, n: x[:n]
accommodation = deploy.normalize_accommodation(
['pair', 'single_room', {'density': 4}, {'compute_nodes': 2}])
actual = deploy.generate_agents(compute_nodes,
accommodation,
unique)
self.assertEqual(8, len(actual))
def test_generate_agents_zones_specified(self):
unique = 'UU1D'
expected = {
'UU1D_master_0': {
'id': 'UU1D_master_0',
'slave_id': 'UU1D_slave_0',
'mode': 'master',
'availability_zone': '%s:uno' % ZONE,
'zone': ZONE,
'node': 'uno'},
'UU1D_slave_0': {
'id': 'UU1D_slave_0',
'master_id': 'UU1D_master_0',
'mode': 'slave',
'availability_zone': '%s:tre' % ZONE,
'zone': ZONE,
'node': 'tre'},
}
nodes = [
{'host': 'uno', 'zone': ZONE},
{'host': 'duo', 'zone': 'other-zone'},
{'host': 'tre', 'zone': ZONE},
]
accommodation = deploy.normalize_accommodation(
['pair', 'single_room', {'zones': [ZONE]}])
actual = deploy.generate_agents(nodes,
accommodation,
unique)
self.assertEqual(expected, actual)
@mock.patch('random.sample')
def test_generate_agents_zones_and_compute_nodes_specified(self, mr):
mr.side_effect = lambda x, n: x[:n]
unique = 'UU1D'
expected = {
'UU1D_master_0': {
'id': 'UU1D_master_0',
'slave_id': 'UU1D_slave_0',
'mode': 'master',
'availability_zone': '%s:uno' % ZONE,
'zone': ZONE,
'node': 'uno'},
'UU1D_slave_0': {
'id': 'UU1D_slave_0',
'master_id': 'UU1D_master_0',
'mode': 'slave',
'availability_zone': '%s:tre' % ZONE,
'zone': ZONE,
'node': 'tre'},
}
nodes = [
{'host': 'uno', 'zone': ZONE},
{'host': 'duo', 'zone': 'other-zone'},
{'host': 'tre', 'zone': ZONE},
{'host': 'cuattro', 'zone': ZONE},
{'host': 'cinco', 'zone': ZONE},
]
accommodation = deploy.normalize_accommodation(
['pair', 'single_room', {'zones': [ZONE]}, {'compute_nodes': 2}])
actual = deploy.generate_agents(nodes,
accommodation,
unique)
self.assertEqual(expected, actual)
def test_generate_agents_cross_zones(self):
unique = 'UU1D'
expected = {
'UU1D_master_0': {
'id': 'UU1D_master_0',
'slave_id': 'UU1D_slave_0',
'mode': 'master',
'availability_zone': 'nova:uno',
'zone': 'nova',
'node': 'uno'},
'UU1D_slave_0': {
'id': 'UU1D_slave_0',
'master_id': 'UU1D_master_0',
'mode': 'slave',
'availability_zone': 'vcenter:tre',
'zone': 'vcenter',
'node': 'tre'},
'UU1D_master_1': {
'id': 'UU1D_master_1',
'slave_id': 'UU1D_slave_1',
'mode': 'master',
'availability_zone': 'nova:duo',
'zone': 'nova',
'node': 'duo'},
'UU1D_slave_1': {
'id': 'UU1D_slave_1',
'master_id': 'UU1D_master_1',
'mode': 'slave',
'availability_zone': 'vcenter:cinco',
'zone': 'vcenter',
'node': 'cinco'},
}
nodes = [
{'host': 'uno', 'zone': 'nova'},
{'host': 'duo', 'zone': 'nova'},
{'host': 'tre', 'zone': 'vcenter'},
{'host': 'quattro', 'zone': 'nova'},
{'host': 'cinco', 'zone': 'vcenter'},
]
accommodation = deploy.normalize_accommodation(
['pair', 'single_room', {'zones': ['nova', 'vcenter']},
'cross_az'])
actual = deploy.generate_agents(nodes, accommodation, unique)
self.assertEqual(expected, actual)
def test_filter_agents_all_deployed(self):
agents = {
'UU1D_agent_0': {
'id': 'UU1D_agent_0',
'mode': 'alone',
'node': 'uno'},
'UU1D_agent_1': {
'id': 'UU1D_agent_1',
'mode': 'alone',
'node': 'dos'},
}
stack_outputs = {
'UU1D_agent_0_ip': '10.0.0.1',
'UU1D_agent_0_instance_name': 'i-000001',
'UU1D_agent_1_ip': '10.0.0.2',
'UU1D_agent_1_instance_name': 'i-000002',
}
filtered = deploy.filter_agents(agents, stack_outputs)
self.assertEqual(agents, filtered)
def test_filter_agents_partial_deployed(self):
agents = {
'UU1D_agent_0': {
'id': 'UU1D_agent_0',
'mode': 'alone',
'node': 'uno'},
'UU1D_agent_1': {
'id': 'UU1D_agent_1',
'mode': 'alone',
'node': 'dos'},
}
stack_outputs = {
'UU1D_agent_0_ip': '10.0.0.1',
'UU1D_agent_0_instance_name': 'i-000001',
}
expected = {'UU1D_agent_0': agents['UU1D_agent_0']}
filtered = deploy.filter_agents(agents, stack_outputs)
self.assertEqual(expected, filtered)
def test_filter_agents_pair_single_room(self):
agents = {
'UU1D_master_0': {
'id': 'UU1D_master_0',
'mode': 'master',
'node': 'uno',
'slave_id': 'UU1D_slave_0'},
'UU1D_slave_0': {
'id': 'UU1D_slave_0',
'master_id': 'UU1D_master_0',
'mode': 'slave',
'node': 'dos'},
}
stack_outputs = {
'UU1D_master_0_ip': '10.0.0.1',
'UU1D_master_0_instance_name': 'i-000001',
'UU1D_slave_0_ip': '10.0.0.2',
'UU1D_slave_0_instance_name': 'i-000002',
}
expected = {'UU1D_master_0': agents['UU1D_master_0'],
'UU1D_slave_0': agents['UU1D_slave_0']}
filtered = deploy.filter_agents(agents, stack_outputs)
self.assertEqual(expected, filtered)
def test_filter_agents_pair_double_room_partially_deployed(self):
agents = {
'UU1D_master_0': {
'id': 'UU1D_master_0',
'mode': 'master',
'node': 'uno',
'slave_id': 'UU1D_slave_0'},
'UU1D_slave_0': {
'id': 'UU1D_slave_0',
'master_id': 'UU1D_master_0',
'mode': 'slave',
'node': 'uno'},
'UU1D_master_1': {
'id': 'UU1D_master_1',
'mode': 'master',
'node': 'dos',
'slave_id': 'UU1D_slave_1'},
'UU1D_slave_1': {
'id': 'UU1D_slave_1',
'master_id': 'UU1D_master_1',
'mode': 'slave',
'node': 'dos'},
}
stack_outputs = {
'UU1D_master_0_ip': '10.0.0.1',
'UU1D_master_0_instance_name': 'i-000001',
'UU1D_slave_0_ip': '10.0.0.2',
'UU1D_slave_0_instance_name': 'i-000002',
'UU1D_master_1_ip': '10.0.0.3',
'UU1D_master_1_instance_name': 'i-000003',
'UU1D_slave_1_instance_name': 'i-000004',
}
expected = {'UU1D_master_0': agents['UU1D_master_0'],
'UU1D_slave_0': agents['UU1D_slave_0'], }
filtered = deploy.filter_agents(agents, stack_outputs)
self.assertEqual(expected, filtered)
def test_filter_agents_pair_single_room_with_overrides(self):
agents = {
'UU1D_master_0': {
'id': 'UU1D_master_0',
'mode': 'master',
'node': 'uno',
'slave_id': 'UU1D_slave_0'},
'UU1D_slave_0': {
'id': 'UU1D_slave_0',
'master_id': 'UU1D_master_0',
'mode': 'slave',
'node': 'dos'},
}
ips = {
'UU1D_master_0': '10.0.0.2',
'UU1D_slave_0': '10.0.0.4',
}
stack_outputs = {}
expected = {'UU1D_master_0': agents['UU1D_master_0'],
'UU1D_slave_0': agents['UU1D_slave_0']}
def override(agent):
return dict(ip=ips[agent['id']])
filtered = deploy.filter_agents(agents, stack_outputs,
override=override)
self.assertEqual(expected, filtered)
self.assertEqual(filtered['UU1D_master_0']['ip'], ips['UU1D_master_0'])
def test_prepare_for_cross_az(self):
source = [
dict(host='uno', zone='nova'),
dict(host='duo', zone='nova'),
dict(host='tre', zone='vcenter'),
]
expected = [
dict(host='uno', zone='nova'),
dict(host='tre', zone='vcenter'),
]
observed = deploy.prepare_for_cross_az(source, ['nova', 'vcenter'])
self.assertEqual(expected, observed)
# Deployment class unit tests
def test_deploy_local(self):
deployment = deploy.Deployment()
expected = {
'local': {'id': 'local', 'mode': 'alone', 'node': 'localhost'}
}
agents = deployment.deploy({})
self.assertEqual(expected, agents)
def test_deploy_static(self):
deployment = deploy.Deployment()
expected = {
'agent': {'id': 'agent', 'mode': 'alone'}
}
agents = deployment.deploy(
{'agents': [{'id': 'agent', 'mode': 'alone'}]})
self.assertEqual(expected, agents)
def test_deploy_template_error_when_non_initialized(self):
deployment = deploy.Deployment()
self.assertRaises(deploy.DeploymentException,
deployment.deploy, {'template': 'foo'})
@mock.patch('shaker.openstack.clients.heat.get_stack_outputs')
@mock.patch('shaker.openstack.clients.heat.create_stack')
@mock.patch('shaker.openstack.clients.openstack.OpenStackClient')
@mock.patch('shaker.engine.deploy.Deployment._get_compute_nodes')
def test_deploy_from_hot_with_env_file(self, nova_nodes_mock,
openstack_mock, create_stack_mock,
stack_output_mock):
test_file = 'shaker/scenarios/test/sample_with_env.yaml'
absolute_path = utils.resolve_relative_path(test_file)
scenario = utils.read_yaml_file(absolute_path)
stack_name = 'shaker_abcdefg'
server_endpoint = "127.0.0.01"
base_dir = os.path.dirname(absolute_path)
deployment = deploy.Deployment()
deployment.stack_name = stack_name
deployment.external_net = 'test-external_net'
deployment.image_name = 'test-image'
deployment.flavor_name = 'test-flavor'
deployment.dns_nameservers = '8.8.8.8'
deployment.openstack_client = openstack_mock
# read the env file to determine what cidr is set to
# minus the last digit
env_file = utils.read_file(scenario['deployment']['env_file'],
base_dir)
cidr = re.findall(r'[0-9]+(?:\.[0-9]+){2}', env_file)[0]
nova_nodes_mock.return_value = [{'host': 'host-1', 'zone': 'nova'}]
create_stack_mock.return_value = uuid.uuid4()
heat_outputs = {
stack_name + '_master_0_instance_name': 'instance-0000052f',
stack_name + '_master_0_ip': '192.0.0.3',
stack_name + '_slave_0_ip': '192.0.0.4',
stack_name + '_slave_0_instance_name': 'instance-0000052c'}
stack_output_mock.return_value = heat_outputs
expected = {
'shaker_abcdefg_master_0': {'availability_zone': 'nova:host-1',
'id': 'shaker_abcdefg_master_0',
'ip': cidr + '.3',
'mode': 'master',
'node': 'host-1',
'slave_id': 'shaker_abcdefg_slave_0',
'zone': 'nova'},
'shaker_abcdefg_slave_0': {'availability_zone': 'nova:host-1',
'id': 'shaker_abcdefg_slave_0',
'ip': cidr + '.4',
'master_id': 'shaker_abcdefg_master_0',
'mode': 'slave',
'node': 'host-1',
'zone': 'nova'}}
agents = deployment._deploy_from_hot(scenario['deployment'],
server_endpoint,
base_dir=base_dir)
self.assertEqual(expected, agents)
@mock.patch('shaker.openstack.clients.heat.get_stack_outputs')
@mock.patch('shaker.openstack.clients.heat.create_stack')
@mock.patch('shaker.openstack.clients.openstack.OpenStackClient')
@mock.patch('shaker.engine.deploy.Deployment._get_compute_nodes')
def test_deploy_from_hot_with_support_stacks(self, nova_nodes_mock,
openstack_mock,
create_stack_mock,
stack_output_mock):
test_file = 'shaker/scenarios/test/sample_with_support_stacks.yaml'
absolute_path = utils.resolve_relative_path(test_file)
scenario = utils.read_yaml_file(absolute_path)
stack_name = 'shaker_abcdefg'
server_endpoint = "127.0.0.01"
base_dir = os.path.dirname(absolute_path)
deployment = deploy.Deployment()
deployment.stack_name = stack_name
deployment.external_net = 'test-external_net'
deployment.image_name = 'test-image'
deployment.flavor_name = 'test-flavor'
deployment.dns_nameservers = '8.8.8.8'
deployment.openstack_client = openstack_mock
nova_nodes_mock.return_value = [{'host': 'host-1', 'zone': 'nova'}]
create_stack_mock.return_value = uuid.uuid4()
heat_outputs = {
stack_name + '_master_0_instance_name': 'instance-0000052f',
stack_name + '_master_0_ip': '10.0.0.3',
stack_name + '_slave_0_ip': '10.0.0.4',
stack_name + '_slave_0_instance_name': 'instance-0000052c'}
stack_output_mock.return_value = heat_outputs
expected = {
'shaker_abcdefg_master_0': {'availability_zone': 'nova:host-1',
'id': 'shaker_abcdefg_master_0',
'ip': '10.0.0.3',
'mode': 'master',
'node': 'host-1',
'slave_id': 'shaker_abcdefg_slave_0',
'zone': 'nova'},
'shaker_abcdefg_slave_0': {'availability_zone': 'nova:host-1',
'id': 'shaker_abcdefg_slave_0',
'ip': '10.0.0.4',
'master_id': 'shaker_abcdefg_master_0',
'mode': 'slave',
'node': 'host-1',
'zone': 'nova'}}
agents = deployment._deploy_from_hot(scenario['deployment'],
server_endpoint,
base_dir=base_dir)
self.assertEqual(create_stack_mock.call_count, 3)
self.assertEqual(expected, agents)
@mock.patch('shaker.openstack.clients.heat.create_stack')
@mock.patch('shaker.openstack.clients.openstack.OpenStackClient')
def test_deploy_support_stacks(self, openstack_mock, create_stack_mock):
test_file = 'shaker/scenarios/test/sample_with_support_stacks.yaml'
absolute_path = utils.resolve_relative_path(test_file)
scenario = utils.read_yaml_file(absolute_path)
support_stacks = scenario['deployment']['support_templates']
base_dir = os.path.dirname(absolute_path)
deployment = deploy.Deployment()
deployment.stack_name = 'shaker_abcdefg'
deployment.openstack_client = openstack_mock
support_stack_1 = uuid.uuid4()
support_stack_2 = uuid.uuid4()
create_stack_mock.side_effect = (support_stack_1, support_stack_2)
deployment._deploy_support_stacks(support_stacks, base_dir)
self.assertEqual(support_stack_1, deployment.support_stacks[0].id)
self.assertEqual(support_stack_2, deployment.support_stacks[1].id)
@mock.patch('shaker.openstack.clients.heat.create_stack')
@mock.patch('shaker.openstack.clients.openstack.OpenStackClient')
def test_deploy_support_stacks_with_conflict(self, openstack_mock,
create_stack_mock):
test_file = 'shaker/scenarios/test/sample_with_support_stacks.yaml'
absolute_path = utils.resolve_relative_path(test_file)
scenario = utils.read_yaml_file(absolute_path)
support_stacks = scenario['deployment']['support_templates']
base_dir = os.path.dirname(absolute_path)
deployment = deploy.Deployment()
deployment.stack_name = 'shaker_abcdefg'
deployment.openstack_client = openstack_mock
support_stack_1 = heat.exc.Conflict
support_stack_2 = uuid.uuid4()
create_stack_mock.side_effect = (support_stack_1, support_stack_2)
deployment._deploy_support_stacks(support_stacks, base_dir)
self.assertEqual(support_stack_2, deployment.support_stacks[0].id)
self.assertEqual(create_stack_mock.call_count, 2)
@mock.patch('shaker.openstack.clients.heat.get_stack_status')
@mock.patch('shaker.openstack.clients.openstack.OpenStackClient')
def test_wait_stack_deletion(self, openstack_mock, get_status_mock):
get_status_mock.side_effect = heat.exc.HTTPNotFound
stack_id = uuid.uuid4()
self.assertIsNone(heat.wait_stack_deletion(openstack_mock, stack_id))
@mock.patch('shaker.openstack.clients.heat.get_stack_status')
@mock.patch('shaker.openstack.clients.openstack.OpenStackClient')
def test_wait_stack_deletion_failed_stack(self, openstack_mock,
get_status_mock):
get_status_mock.return_value = ('FAILED', 'some_reason')
stack_id = uuid.uuid4()
self.assertRaises(heat.exc.StackFailure, heat.wait_stack_deletion,
openstack_mock, stack_id)
@mock.patch('shaker.openstack.clients.heat.get_stack_status')
@mock.patch('shaker.openstack.clients.openstack.OpenStackClient')
def test_wait_stack_deletion_timeout(self, openstack_mock,
get_status_mock):
get_status_mock.side_effect = TimeoutError
stack_id = uuid.uuid4()
self.assertIsNone(heat.wait_stack_deletion(openstack_mock, stack_id))
@mock.patch('shaker.openstack.clients.openstack.OpenStackClient')
def test_get_compute_nodes_flavor_no_extra_specs(self,
nova_client_mock):
# setup fake nova api service list response
compute_host_1 = fakes.FakeNovaServiceList(host='host-1')
compute_host_2 = fakes.FakeNovaServiceList(host='host-2')
compute_host_3 = fakes.FakeNovaServiceList(host='host-3')
nova_client_mock.nova.services.list.return_value = [compute_host_1,
compute_host_2,
compute_host_3]
# setup fake nova api flavor list response
flavor_no_exta_specs = fakes.FakeNovaFlavorList(
name='flavor_no_exta_specs')
nova_client_mock.nova.flavors.list.return_value = [
flavor_no_exta_specs]
deployment = deploy.Deployment()
deployment.flavor_name = 'flavor_no_exta_specs'
deployment.openstack_client = nova_client_mock
accommodation = {'compute_nodes': 3}
expected = [{'host': 'host-1', 'zone': 'nova'},
{'host': 'host-2', 'zone': 'nova'},
{'host': 'host-3', 'zone': 'nova'}]
observed = deployment._get_compute_nodes(accommodation)
self.assertEqual(expected, observed)
@mock.patch('shaker.openstack.clients.openstack.OpenStackClient')
def test_get_compute_nodes_flavor_extra_specs_no_match(self,
nova_client_mock):
# setup fake nova api service list response
compute_host_1 = fakes.FakeNovaServiceList(host='host-1')
compute_host_2 = fakes.FakeNovaServiceList(host='host-2')
compute_host_3 = fakes.FakeNovaServiceList(host='host-3')
nova_client_mock.nova.services.list.return_value = [compute_host_1,
compute_host_2,
compute_host_3]
# setup fake nova api flavor list response
flavor_with_extra_specs = fakes.FakeNovaFlavorList(
name='flavor_with_extra_specs',
extra_specs={'aggregate_instance_extra_specs:other_hw': 'false'})
nova_client_mock.nova.flavors.list.return_value = [
flavor_with_extra_specs]
# setup fake nova api aggregate list response
agg_host_1 = fakes.FakeNovaAggregateList(hosts=['host-1'], metadata={
'special_hw': 'true'})
agg_host_2 = fakes.FakeNovaAggregateList(hosts=['host-2'])
agg_host_3 = fakes.FakeNovaAggregateList(hosts=['host-3'])
nova_client_mock.nova.aggregates.list.return_value = [agg_host_1,
agg_host_2,
agg_host_3]
deployment = deploy.Deployment()
deployment.flavor_name = 'flavor_with_extra_specs'
deployment.openstack_client = nova_client_mock
accommodation = {'compute_nodes': 3}
expected = []
observed = deployment._get_compute_nodes(accommodation)
self.assertEqual(expected, observed)
@mock.patch('shaker.openstack.clients.openstack.OpenStackClient')
def test_get_compute_nodes_flavor_extra_specs_with_match(self,
nova_client_mock):
# setup fake nova api service list response
compute_host_1 = fakes.FakeNovaServiceList(host='host-1')
compute_host_2 = fakes.FakeNovaServiceList(host='host-2')
compute_host_3 = fakes.FakeNovaServiceList(host='host-3')
nova_client_mock.nova.services.list.return_value = [compute_host_1,
compute_host_2,
compute_host_3]
# setup fake nova api flavor list response
flavor_with_extra_specs = fakes.FakeNovaFlavorList(
name='flavor_with_extra_specs',
extra_specs={'aggregate_instance_extra_specs:special_hw': 'true'})
nova_client_mock.nova.flavors.list.return_value = [
flavor_with_extra_specs]
# setup fake nova api aggregate list response
agg_host_1 = fakes.FakeNovaAggregateList(hosts=['host-1'])
agg_host_2 = fakes.FakeNovaAggregateList(hosts=['host-2'], metadata={
'special_hw': 'true'})
agg_host_3 = fakes.FakeNovaAggregateList(hosts=['host-3'])
nova_client_mock.nova.aggregates.list.return_value = [agg_host_1,
agg_host_2,
agg_host_3]
deployment = deploy.Deployment()
deployment.flavor_name = 'flavor_with_extra_specs'
deployment.openstack_client = nova_client_mock
accommodation = {'compute_nodes': 3}
expected = [{'host': 'host-2', 'zone': 'nova'}]
observed = deployment._get_compute_nodes(accommodation)
self.assertEqual(expected, observed)
@mock.patch('shaker.openstack.clients.nova.get_available_compute_nodes')
def test_get_compute_nodes_non_admin(self, nova_nodes_mock):
deployment = deploy.Deployment()
deployment.flavor_name = 'test.flavor'
deployment.openstack_client = mock.Mock()
def raise_error(nova_client, flavor_name):
raise nova.ForbiddenException('err')
nova_nodes_mock.side_effect = raise_error
accommodation = {'compute_nodes': 4}
expected = list(itertools.repeat({'host': None, 'zone': 'nova'}, 4))
observed = deployment._get_compute_nodes(accommodation)
self.assertEqual(expected, observed)
@mock.patch('shaker.openstack.clients.nova.get_available_compute_nodes')
def test_get_compute_nodes_non_admin_zones(self, nova_nodes_mock):
deployment = deploy.Deployment()
deployment.flavor_name = 'test.flavor'
deployment.openstack_client = mock.Mock()
def raise_error(nova_client, flavor_name):
raise nova.ForbiddenException('err')
nova_nodes_mock.side_effect = raise_error
accommodation = {'compute_nodes': 4, 'zones': ['nova', 'nsx']}
expected = [
{'host': None, 'zone': 'nova'},
{'host': None, 'zone': 'nsx'},
{'host': None, 'zone': 'nova'},
{'host': None, 'zone': 'nsx'},
]
observed = deployment._get_compute_nodes(accommodation)
self.assertEqual(expected, observed)
@mock.patch('shaker.openstack.clients.nova.get_available_compute_nodes')
def test_get_compute_nodes_non_admin_not_configured(self, nova_nodes_mock):
deployment = deploy.Deployment()
deployment.flavor_name = 'test.flavor'
deployment.openstack_client = mock.Mock()
def raise_error(nova_client, flavor_name):
raise nova.ForbiddenException('err')
nova_nodes_mock.side_effect = raise_error
accommodation = {}
self.assertRaises(deploy.DeploymentException,
deployment._get_compute_nodes, accommodation)
def test_normalize_accommodation(self):
origin = ['pair', 'single_room', {'compute_nodes': 2}]
expected = collections.OrderedDict()
expected['pair'] = True
expected['single_room'] = True
expected['compute_nodes'] = 2
self.assertEqual(expected, deploy.normalize_accommodation(origin))
def test_override_single_scenario_availability_zone(self):
origin = ['pair', {'zones': ['nova']}]
self.config_fixture.config(scenario_availability_zone='test')
expected = collections.OrderedDict()
expected['pair'] = True
expected['zones'] = ['test']
self.assertEqual(expected, deploy.normalize_accommodation(origin))
def test_override_list_scenario_availability_zone(self):
origin = ['pair', {'zones': ['nova']}]
self.config_fixture.config(scenario_availability_zone='test1, test2')
expected = collections.OrderedDict()
expected['pair'] = True
expected['zones'] = ['test1', 'test2']
self.assertEqual(expected, deploy.normalize_accommodation(origin))
def test_override_scenario_compute_nodes(self):
origin = ['pair', {'compute_nodes': 1}]
self.config_fixture.config(scenario_compute_nodes=5)
expected = collections.OrderedDict()
expected['pair'] = True
expected['compute_nodes'] = 5
self.assertEqual(expected, deploy.normalize_accommodation(origin))
def test_distribute_agents(self):
agents = {
'UU1D_master_0': {
'id': 'UU1D_master_0',
'mode': 'master',
'ip': '10.0.0.3',
'slave_id': 'UU1D_slave_0'},
'UU1D_slave_0': {
'id': 'UU1D_slave_0',
'master_id': 'UU1D_master_0',
'ip': '10.0.0.4',
'mode': 'slave'},
'UU1D_master_1': {
'id': 'UU1D_master_1',
'mode': 'master',
'ip': '10.0.0.5',
'slave_id': 'UU1D_slave_1'},
'UU1D_slave_1': {
'id': 'UU1D_slave_1',
'master_id': 'UU1D_master_1',
'ip': '10.0.0.6',
'mode': 'slave'},
}
hosts = {
'UU1D_master_0': '001',
'UU1D_slave_0': '002',
'UU1D_master_1': '003',
'UU1D_slave_1': '004',
}
expected = copy.deepcopy(agents)
for k, v in hosts.items():
expected[k]['node'] = v
observed = deploy.distribute_agents(agents, lambda x: hosts[x])
# expected no changes
self.assertEqual(agents, observed)
# todo refactor code to use lists instead of dicts
def _test_distribute_agents_collision(self):
agents = {
'UU1D_master_0': {
'id': 'UU1D_master_0',
'mode': 'master',
'ip': '10.0.0.3',
'slave_id': 'UU1D_slave_0'},
'UU1D_slave_0': {
'id': 'UU1D_slave_0',
'master_id': 'UU1D_master_0',
'ip': '10.0.0.4',
'mode': 'slave'},
'UU1D_master_1': {
'id': 'UU1D_master_1',
'mode': 'master',
'ip': '10.0.0.5',
'slave_id': 'UU1D_slave_1'},
'UU1D_slave_1': {
'id': 'UU1D_slave_1',
'master_id': 'UU1D_master_1',
'ip': '10.0.0.6',
'mode': 'slave'},
}
hosts = {
'UU1D_master_0': '001',
'UU1D_slave_0': '001', # collides with master_0
'UU1D_master_1': '003',
'UU1D_slave_1': '004',
}
expected = {
'UU1D_master_0': {
'id': 'UU1D_master_0',
'mode': 'master',
'ip': '10.0.0.3',
'node': '001',
'slave_id': 'UU1D_slave_1'},
'UU1D_slave_1': {
'id': 'UU1D_slave_1',
'master_id': 'UU1D_master_0',
'ip': '10.0.0.6',
'node': '004',
'mode': 'slave'},
}
observed = deploy.distribute_agents(agents, lambda x: hosts[x])
self.assertEqual(expected, observed)