fuel-web/nailgun/nailgun/test/integration/test_orchestrator_serialize...

2753 lines
109 KiB
Python

# -*- coding: utf-8 -*-
# Copyright 2013 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 copy
from operator import attrgetter
from operator import itemgetter
from random import randint
import re
import six
from six.moves import range
import mock
from netaddr import IPAddress
from netaddr import IPNetwork
from netaddr import IPRange
from oslo_serialization import jsonutils
import yaml
from nailgun import consts
from nailgun.db.sqlalchemy.models import Cluster
from nailgun.db.sqlalchemy.models import NetworkGroup
from nailgun.db.sqlalchemy.models import Node
from nailgun.orchestrator.deployment_serializers import \
deployment_info_to_legacy
from nailgun.orchestrator.deployment_serializers import\
DeploymentHASerializer
from nailgun.orchestrator.deployment_serializers import\
DeploymentHASerializer50
from nailgun.orchestrator.deployment_serializers import\
DeploymentHASerializer51
from nailgun.orchestrator.deployment_serializers import\
DeploymentHASerializer61
from nailgun.orchestrator.deployment_serializers import\
DeploymentMultinodeSerializer
from nailgun.orchestrator.deployment_serializers import\
DeploymentMultinodeSerializer50
from nailgun.orchestrator.deployment_serializers import\
DeploymentMultinodeSerializer61
from nailgun.orchestrator.deployment_serializers import\
get_serializer_for_cluster
from nailgun.orchestrator.orchestrator_graph import AstuteGraph
from nailgun.db.sqlalchemy import models
from nailgun import objects
from nailgun.settings import settings
from nailgun.test import base
from nailgun.utils import reverse
class BaseSerializerTest(base.BaseIntegrationTest):
@classmethod
def create_serializer(cls, cluster):
return get_serializer_for_cluster(cluster)(AstuteGraph(cluster))
class OrchestratorSerializerTestBase(BaseSerializerTest):
"""Class contains helpers."""
def setUp(self):
super(OrchestratorSerializerTestBase, self).setUp()
self.cluster_mock = mock.MagicMock()
self.cluster_mock.id = 0
self.cluster_mock.deployment_tasks = []
self.cluster_mock.release.deployment_tasks = []
self.common_attrs = mock.MagicMock()
def filter_by_role(self, nodes, role):
return filter(lambda node: role in node['role'], nodes)
def filter_by_uid(self, nodes, uid):
return filter(lambda node: node['uid'] == uid, nodes)
def assert_nodes_with_role(self, nodes, role, count):
self.assertEqual(len(self.filter_by_role(nodes, role)), count)
def get_controllers(self, cluster_id):
return self.db.query(Node).\
filter_by(cluster_id=cluster_id,
pending_deletion=False).\
filter(Node.roles.any('controller')).\
order_by(Node.id)
def add_default_params(self, nodes):
"""Adds necessary default parameters to nodes
:param nodes: list of dicts
"""
for pos, node in enumerate(nodes, start=1):
node['uid'] = str(pos)
@property
def serializer(self):
self.cluster_mock.release.environment_version = '5.0'
return DeploymentHASerializer(AstuteGraph(self.cluster_mock))
def serialize(self, cluster):
objects.Cluster.prepare_for_deployment(cluster)
return self.serializer.serialize(cluster, cluster.nodes)
def move_network(self, node_id, net_name, from_if, to_if):
resp = self.app.get(
reverse("NodeNICsHandler",
kwargs={"node_id": node_id}),
headers=self.default_headers)
self.assertEqual(resp.status_code, 200)
data = resp.json_body
net_from = None
for nic in data:
if nic['name'] == from_if:
net_from = [n for n in nic['assigned_networks']
if n['name'] == net_name]
if net_from:
nic['assigned_networks'] = \
[n for n in nic['assigned_networks']
if n != net_from[0]]
self.assertIsNotNone(net_from)
for nic in data:
if nic['name'] == to_if:
nic['assigned_networks'].append(net_from[0])
resp = self.env.node_nics_put(node_id, data)
self.assertEqual(resp.status_code, 200)
def check_ep_format(self, endpoint_list):
for ep in endpoint_list.values():
if ep.get('IP'):
self.assertTrue(
ep['IP'] == 'none' or isinstance(ep['IP'], list))
class TestReplacedDeploymentInfoSerialization(OrchestratorSerializerTestBase):
env_version = '1111-6.0'
def setUp(self):
super(TestReplacedDeploymentInfoSerialization, self).setUp()
self.cluster = self.env.create(
release_kwargs={'version': self.env_version},
cluster_kwargs={'api': False})
objects.Cluster.set_primary_tags(self.cluster, self.cluster.nodes)
def test_replaced_tasks_is_not_preserved(self):
node = self.env.create_node(
api=False,
cluster_id=self.cluster.id,
pending_addition=True,
roles=['controller'])
node.replaced_deployment_info = [
{'role': 'controller', 'priority': 'XXX', 'tasks': [], 'uid': '1'}]
self.db.flush()
objects.Cluster.prepare_for_deployment(
self.cluster, self.cluster.nodes
)
serialized_data = self.serializer.serialize(self.cluster, [node])
# verify that task list is not empty
self.assertTrue(serialized_data['nodes'][0]['tasks'])
# verify that priority is preserved
self.assertEqual(serialized_data['nodes'][0]['priority'], 'XXX')
# TODO(awoodward): multinode deprecation: probably has duplicates
class TestNovaOrchestratorSerializer(OrchestratorSerializerTestBase):
env_version = '1111-6.0'
def setUp(self):
super(TestNovaOrchestratorSerializer, self).setUp()
self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
objects.Cluster.set_primary_tags(self.cluster, self.cluster.nodes)
def create_env(self, mode, network_manager='FlatDHCPManager'):
node_args = [
{'roles': ['controller', 'cinder'], 'pending_addition': True},
{'roles': ['compute', 'cinder'], 'pending_addition': True},
{'roles': ['compute'], 'pending_addition': True},
{'roles': ['mongo'], 'pending_addition': True},
{'roles': [], 'pending_roles': ['cinder'],
'pending_addition': True}]
cluster = self.env.create(
release_kwargs={'version': self.env_version},
cluster_kwargs={
'mode': mode,
'net_manager': network_manager,
'net_provider': consts.CLUSTER_NET_PROVIDERS.nova_network},
nodes_kwargs=node_args)
cluster_db = self.db.query(Cluster).get(cluster['id'])
objects.Cluster.prepare_for_deployment(cluster_db)
self.db.flush()
return cluster_db
def assert_roles_flattened(self, nodes):
self.assertEqual(len(nodes), 7)
self.assert_nodes_with_role(nodes, 'controller', 1)
self.assert_nodes_with_role(nodes, 'compute', 2)
self.assert_nodes_with_role(nodes, 'cinder', 3)
self.assert_nodes_with_role(nodes, 'mongo', 1)
def test_serialize_nodes(self):
serialized_nodes = self.serializer.serialize_nodes(self.cluster.nodes)
self.assert_roles_flattened(serialized_nodes)
# Each not should be same as result of
# serialize_node function
for serialized_node in serialized_nodes:
node_db = self.db.query(Node).get(int(serialized_node['uid']))
expected_node = self.serializer.serialize_node(
node_db, serialized_node['role']
)
self.assertEqual(serialized_node, expected_node)
def test_serialize_node(self):
node = self.env.create_node(
api=True, cluster_id=self.cluster.id, pending_addition=True)
objects.Cluster.prepare_for_deployment(self.cluster)
self.db.flush()
node_db = self.db.query(Node).get(node['id'])
serialized_data = self.serializer.serialize_node(
node_db, 'controller'
)
self.assertEqual(serialized_data['role'], 'controller')
self.assertEqual(serialized_data['uid'], str(node_db.id))
self.assertEqual(serialized_data['status'], node_db.status)
self.assertEqual(serialized_data['online'], node_db.online)
self.assertEqual(serialized_data['fqdn'],
'%s.%s' % (node_db.hostname, settings.DNS_DOMAIN))
def test_serialize_node_vms_conf(self):
node = self.env.create_node(
api=True, cluster_id=self.cluster.id, pending_addition=True)
objects.Cluster.prepare_for_deployment(self.cluster)
self.db.flush()
node_db = self.db.query(Node).get(node['id'])
vms_conf = [{'id': 1, 'cluster_id': self.cluster.id}]
node_db.vms_conf = vms_conf
serialized_data = self.serializer.serialize_node(
node_db, 'controller'
)
self.assertEqual(serialized_data['vms_conf'], vms_conf)
def test_node_list(self):
node_list = self.serializer.get_common_attrs(self.cluster)['nodes']
# Check right nodes count with right roles
self.assert_roles_flattened(node_list)
# Check common attrs
for node in node_list:
node_db = self.db.query(Node).get(int(node['uid']))
self.assertEqual(node['public_netmask'], '255.255.255.0')
self.assertEqual(node['internal_netmask'], '255.255.255.0')
self.assertEqual(node['storage_netmask'], '255.255.255.0')
self.assertEqual(node['uid'], str(node_db.id))
self.assertEqual(node['name'], '%s' % node_db.hostname)
self.assertEqual(node['fqdn'], '%s.%s' %
(node_db.hostname, settings.DNS_DOMAIN))
# Check uncommon attrs
# Convert ids to int to have correct order in the set
node_uids = sorted(set([int(n['uid']) for n in node_list]))
man_ip = [str(ip) for ip in IPRange('192.168.0.1', '192.168.0.5')]
pub_ip = [str(ip) for ip in IPRange('172.16.0.2', '172.16.0.6')]
sto_ip = [str(ip) for ip in IPRange('192.168.1.1', '192.168.1.5')]
expected_list = [
{'roles': ['controller', 'cinder']},
{'roles': ['compute', 'cinder']},
{'roles': ['compute']},
{'roles': ['mongo']},
{'roles': ['cinder']}]
for i in range(len(expected_list)):
expected_list[i]['attrs'] = {'uid': str(node_uids[i])}
used_man_ip = []
used_pub_ip = []
used_sto_ip = []
for expected in expected_list:
attrs = expected['attrs']
ref_node = self.filter_by_uid(node_list, attrs['uid'])[0]
self.assertTrue(ref_node['internal_address'] in man_ip)
self.assertTrue(ref_node['public_address'] in pub_ip)
self.assertTrue(ref_node['storage_address'] in sto_ip)
self.assertFalse(ref_node['internal_address'] in used_man_ip)
self.assertFalse(ref_node['public_address'] in used_pub_ip)
self.assertFalse(ref_node['storage_address'] in used_sto_ip)
used_man_ip.append(ref_node['internal_address'])
used_pub_ip.append(ref_node['public_address'])
used_sto_ip.append(ref_node['storage_address'])
for role in expected['roles']:
nodes = self.filter_by_role(node_list, role)
node = self.filter_by_uid(nodes, attrs['uid'])[0]
self.assertEqual(node['public_address'],
ref_node['public_address'])
self.assertEqual(node['storage_address'],
ref_node['storage_address'])
self.assertEqual(node['internal_address'],
ref_node['internal_address'])
def test_flatdhcp_manager(self):
facts = self.serializer.serialize(self.cluster, self.cluster.nodes)
common = facts['common']
self.assertEqual(
common['novanetwork_parameters']['network_manager'],
'FlatDHCPManager')
self.assertEqual(
common['novanetwork_parameters']['num_networks'], 1)
self.assertEqual(
common['novanetwork_parameters']['network_size'], 65536)
def test_vlan_manager(self):
data = {'networking_parameters': {'net_manager': 'VlanManager'}}
url = reverse('NovaNetworkConfigurationHandler',
kwargs={'cluster_id': self.cluster.id})
self.app.put(url, jsonutils.dumps(data),
headers=self.default_headers,
expect_errors=False)
facts = self.serializer.serialize(self.cluster, self.cluster.nodes)
common = facts['common']
facts = facts['nodes']
for fact in facts:
self.assertEqual(fact['vlan_interface'], 'eth0')
self.assertEqual(fact['fixed_interface'], 'eth0')
self.assertEqual(
common['novanetwork_parameters']['network_manager'],
'VlanManager')
self.assertEqual(
common['novanetwork_parameters']['num_networks'], 1)
self.assertEqual(
common['novanetwork_parameters']['vlan_start'], 103)
self.assertEqual(
common['novanetwork_parameters']['network_size'], 256)
def test_floating_ranges_generation(self):
# Set ip ranges for floating ips
ranges = [['172.16.0.2', '172.16.0.4'],
['172.16.0.3', '172.16.0.5'],
['172.16.0.10', '172.16.0.12']]
self.cluster.network_config.floating_ranges = ranges
self.db.commit()
facts = self.serializer.serialize(self.cluster, self.cluster.nodes)
facts = deployment_info_to_legacy(facts)
for fact in facts:
self.assertEqual(
fact['floating_network_range'],
['172.16.0.2-172.16.0.4',
'172.16.0.3-172.16.0.5',
'172.16.0.10-172.16.0.12'])
def test_configure_interfaces_untagged_network(self):
for network in self.db.query(NetworkGroup).all():
network.vlan_start = None
self.cluster.network_config.fixed_networks_vlan_start = None
self.db.commit()
node_db = sorted(self.cluster.nodes, key=lambda n: n.id)[0]
from nailgun.extensions.network_manager.serializers.nova_serializers \
import NovaNetworkDeploymentSerializer
interfaces = NovaNetworkDeploymentSerializer.\
configure_interfaces(node_db)
expected_interfaces = {
'lo': {
'interface': 'lo',
'ipaddr': ['127.0.0.1/8']
},
'eth1': {
'interface': 'eth1',
'ipaddr': ['172.16.0.2/24'],
'gateway': '172.16.0.1',
'default_gateway': True
},
'eth0': {
'interface': 'eth0',
'ipaddr': ['192.168.0.1/24',
'192.168.1.1/24',
'10.20.0.129/24'],
}
}
self.datadiff(expected_interfaces, interfaces, ignore_keys=['ipaddr'])
def test_set_deployment_priorities(self):
nodes = [
{'role': 'mongo'},
{'role': 'mongo'},
{'role': 'primary-mongo'},
{'role': 'controller'},
{'role': 'ceph-osd'}
]
self.add_default_params(nodes)
self.cluster_mock.release.environment_version = '5.0'
serializer = DeploymentMultinodeSerializer(
AstuteGraph(self.cluster_mock))
serializer.set_deployment_priorities(nodes)
expected_priorities = [
{'role': 'mongo', 'priority': 100},
{'role': 'mongo', 'priority': 200},
{'role': 'primary-mongo', 'priority': 300},
{'role': 'controller', 'priority': 400},
{'role': 'ceph-osd', 'priority': 500}
]
self.add_default_params(expected_priorities)
self.assertEqual(expected_priorities, nodes)
def test_set_critital_node(self):
self.cluster_mock.release.environment_version = '5.0'
serializer = DeploymentMultinodeSerializer(
AstuteGraph(self.cluster_mock))
serialized_nodes = serializer.serialize_nodes(self.cluster.nodes)
# primary-contoller is not critical for MultiNode serializer
expected_ciritial_roles = [
{'fail_if_error': False, 'role': 'cinder'},
{'fail_if_error': False, 'role': 'primary-controller'},
{'fail_if_error': False, 'role': 'cinder'},
{'fail_if_error': False, 'role': 'compute'},
{'fail_if_error': False, 'role': 'compute'},
{'fail_if_error': True, 'role': 'primary-mongo'},
{'fail_if_error': False, 'role': 'cinder'}
]
self.assertItemsEqual(
expected_ciritial_roles,
[
{'role': n['role'], 'fail_if_error': n['fail_if_error']}
for n in serialized_nodes
]
)
class TestNovaNetworkOrchestratorSerializer61(OrchestratorSerializerTestBase):
env_version = '2014.2-6.1'
def create_env(self, manager, nodes_count=3, ctrl_count=1, nic_count=2):
cluster = self.env.create(
release_kwargs={'version': self.env_version},
cluster_kwargs={
'mode': consts.CLUSTER_MODES.ha_compact,
'net_provider': consts.CLUSTER_NET_PROVIDERS.nova_network})
data = {'networking_parameters': {'net_manager': manager}}
self.env.nova_networks_put(cluster['id'], data)
self.env.create_nodes_w_interfaces_count(
nodes_count=ctrl_count,
if_count=nic_count,
roles=['controller', 'cinder'],
pending_addition=True,
cluster_id=cluster['id'])
self.env.create_nodes_w_interfaces_count(
nodes_count=nodes_count - ctrl_count,
if_count=nic_count,
roles=['compute'],
pending_addition=True,
cluster_id=cluster['id'])
cluster_db = self.db.query(Cluster).get(cluster['id'])
objects.Cluster.prepare_for_deployment(cluster_db)
objects.Cluster.set_primary_tags(cluster_db, cluster_db.nodes)
self.db.flush()
return cluster_db
def test_flat_dhcp_schema(self):
cluster = self.create_env(
manager=consts.NOVA_NET_MANAGERS.FlatDHCPManager
)
serializer = self.create_serializer(cluster)
facts = serializer.serialize(cluster, cluster.nodes)['nodes']
for node in facts:
scheme = node['network_scheme']
self.assertEqual(
set(scheme.keys()),
set(['version', 'provider', 'interfaces',
'endpoints', 'roles', 'transformations'])
)
self.assertEqual(scheme['version'], '1.1')
self.assertEqual(scheme['provider'], 'lnx')
self.assertEqual(
set(scheme['interfaces'].keys()),
set(['eth0', 'eth1'])
)
self.assertEqual(
set(scheme['endpoints'].keys()),
set(['br-storage', 'br-mgmt', 'br-fw-admin', 'br-ex',
'eth0.103'])
)
self.check_ep_format(scheme['endpoints'])
self.assertEqual(
scheme['roles'],
{'storage': 'br-storage',
'management': 'br-mgmt',
'fw-admin': 'br-fw-admin',
'ex': 'br-ex',
'novanetwork/fixed': 'eth0.103'}
)
self.assertEqual(
scheme['transformations'],
[
{'action': 'add-br',
'name': 'br-fw-admin'},
{'action': 'add-br',
'name': 'br-storage'},
{'action': 'add-br',
'name': 'br-mgmt'},
{'action': 'add-br',
'name': 'br-ex'},
{'action': 'add-port',
'bridge': 'br-fw-admin',
'name': 'eth0'},
{'action': 'add-port',
'bridge': 'br-storage',
'name': 'eth0.102'},
{'action': 'add-port',
'bridge': 'br-mgmt',
'name': 'eth0.101'},
{'action': 'add-port',
'bridge': 'br-ex',
'name': 'eth1'},
{'action': 'add-port',
'name': 'eth0.103'},
]
)
def test_vlan_schema(self):
cluster = self.create_env(
manager=consts.NOVA_NET_MANAGERS.VlanManager
)
serializer = self.create_serializer(cluster)
facts = serializer.serialize(cluster, cluster.nodes)['nodes']
for node in facts:
scheme = node['network_scheme']
self.assertEqual(
set(scheme.keys()),
set(['version', 'provider', 'interfaces',
'endpoints', 'roles', 'transformations'])
)
self.assertEqual(scheme['version'], '1.1')
self.assertEqual(scheme['provider'], 'lnx')
self.assertEqual(
set(scheme['interfaces'].keys()),
set(['eth0', 'eth1'])
)
self.assertEqual(
set(scheme['endpoints'].keys()),
set(['br-storage', 'br-mgmt', 'br-fw-admin', 'br-ex',
'eth0'])
)
self.check_ep_format(scheme['endpoints'])
self.assertEqual(
scheme['roles'],
{'storage': 'br-storage',
'management': 'br-mgmt',
'fw-admin': 'br-fw-admin',
'ex': 'br-ex',
'novanetwork/vlan': 'eth0'}
)
self.assertEqual(
scheme['transformations'],
[
{'action': 'add-br',
'name': 'br-fw-admin'},
{'action': 'add-br',
'name': 'br-storage'},
{'action': 'add-br',
'name': 'br-mgmt'},
{'action': 'add-br',
'name': 'br-ex'},
{'action': 'add-port',
'bridge': 'br-fw-admin',
'name': 'eth0'},
{'action': 'add-port',
'bridge': 'br-storage',
'name': 'eth0.102'},
{'action': 'add-port',
'bridge': 'br-mgmt',
'name': 'eth0.101'},
{'action': 'add-port',
'bridge': 'br-ex',
'name': 'eth1'},
]
)
def test_flat_dhcp_with_bonds(self):
cluster = self.create_env(
manager=consts.NOVA_NET_MANAGERS.FlatDHCPManager,
ctrl_count=3,
nic_count=3
)
for node in cluster.nodes:
self.move_network(node.id, 'management', 'eth0', 'eth1')
self.env.make_bond_via_api(
'lnx_bond', '', ['eth1', 'eth2'], node.id,
attrs={
'type__': {'value': consts.BOND_TYPES.linux},
'mode': {
'value': {'value': consts.BOND_MODES.balance_rr}}})
serializer = self.create_serializer(cluster)
facts = serializer.serialize(cluster, cluster.nodes)['nodes']
for node in facts:
self.assertEqual(
node['network_scheme']['transformations'],
[
{'action': 'add-br',
'name': 'br-fw-admin'},
{'action': 'add-br',
'name': 'br-storage'},
{'action': 'add-br',
'name': 'br-mgmt'},
{'action': 'add-br',
'name': 'br-ex'},
{'action': 'add-port',
'bridge': 'br-fw-admin',
'name': 'eth0'},
{'action': 'add-port',
'bridge': 'br-storage',
'name': 'eth0.102'},
{'action': 'add-bond',
'bridge': 'br-ex',
'name': 'lnx_bond',
'interfaces': ['eth1', 'eth2'],
'bond_properties': {'mode': 'balance-rr'},
'interface_properties': {}},
{'action': 'add-port',
'bridge': 'br-mgmt',
'name': 'lnx_bond.101'},
{'action': 'add-port',
'name': 'eth0.103'},
]
)
def test_vlan_with_bonds(self):
cluster = self.create_env(
manager=consts.NOVA_NET_MANAGERS.VlanManager,
ctrl_count=3,
nic_count=3
)
for node in cluster.nodes:
self.move_network(node.id, 'management', 'eth0', 'eth1')
self.move_network(node.id, 'fixed', 'eth0', 'eth1')
self.env.make_bond_via_api(
'lnx_bond', '', ['eth1', 'eth2'], node.id,
attrs={
'type__': {'value': consts.BOND_TYPES.linux},
'mode': {
'value': {'value': consts.BOND_MODES.balance_rr}}})
serializer = self.create_serializer(cluster)
facts = serializer.serialize(cluster, cluster.nodes)['nodes']
for node in facts:
self.assertEqual(
node['network_scheme']['roles'],
{'storage': 'br-storage',
'management': 'br-mgmt',
'fw-admin': 'br-fw-admin',
'ex': 'br-ex',
'novanetwork/vlan': 'lnx_bond'}
)
self.assertEqual(
node['network_scheme']['transformations'],
[
{'action': 'add-br',
'name': 'br-fw-admin'},
{'action': 'add-br',
'name': 'br-storage'},
{'action': 'add-br',
'name': 'br-mgmt'},
{'action': 'add-br',
'name': 'br-ex'},
{'action': 'add-port',
'bridge': 'br-fw-admin',
'name': 'eth0'},
{'action': 'add-port',
'bridge': 'br-storage',
'name': 'eth0.102'},
{'action': 'add-bond',
'bridge': 'br-ex',
'name': 'lnx_bond',
'interfaces': ['eth1', 'eth2'],
'bond_properties': {'mode': 'balance-rr'},
'interface_properties': {}},
{'action': 'add-port',
'bridge': 'br-mgmt',
'name': 'lnx_bond.101'},
]
)
class TestNeutronOrchestratorSerializer61(OrchestratorSerializerTestBase):
env_version = '2014.2-6.1'
def create_env(self, segment_type, nodes_count=3, ctrl_count=1,
nic_count=2):
cluster = self.env.create(
release_kwargs={'version': self.env_version},
cluster_kwargs={
'mode': consts.CLUSTER_MODES.ha_compact,
'net_provider': 'neutron',
'net_segment_type': segment_type}
)
self.env.create_nodes_w_interfaces_count(
nodes_count=ctrl_count,
if_count=nic_count,
roles=['controller', 'cinder'],
pending_addition=True,
cluster_id=cluster['id'])
self.env.create_nodes_w_interfaces_count(
nodes_count=nodes_count - ctrl_count,
if_count=nic_count,
roles=['compute'],
pending_addition=True,
cluster_id=cluster['id'])
cluster_db = self.db.query(Cluster).get(cluster['id'])
objects.Cluster.prepare_for_deployment(cluster_db)
objects.Cluster.set_primary_tags(cluster_db, cluster_db.nodes)
self.db.flush()
return cluster_db
def add_nics_properties(self, cluster):
nodes_list = []
for node in cluster.nodes:
resp = self.app.get(
reverse('NodeNICsHandler', kwargs={'node_id': node.id}),
headers=self.default_headers
)
self.assertEquals(200, resp.status_code)
interfaces = jsonutils.loads(resp.body)
for iface in interfaces:
if iface['name'] == 'eth0':
iface['attributes']['mtu']['value']['value'] = 1500
iface['attributes']['offloading'][
'disable']['value'] = True
nodes_list.append({'id': node.id, 'interfaces': interfaces})
resp_put = self.app.put(
reverse('NodeCollectionNICsHandler'),
jsonutils.dumps(nodes_list),
headers=self.default_headers
)
self.assertEqual(resp_put.status_code, 200)
def check_gateways(self, node, scheme, is_public):
nm = objects.Cluster.get_network_manager(node.cluster)
ep = scheme['endpoints']
if is_public:
gw = nm.get_network_by_netname(
'public', nm.get_node_networks(node))['gateway']
self.assertEqual(ep['br-ex']['gateway'], gw)
else:
gw = nm.get_default_gateway(node.id)
self.assertEqual(ep['br-fw-admin']['gateway'], gw)
def check_vlan_schema(self, facts, transformations):
for node in facts:
node_db = objects.Node.get_by_uid(node['uid'])
is_public = objects.Node.should_have_public(node_db)
scheme = node['network_scheme']
self.assertEqual(
set(scheme.keys()),
set(['version', 'provider', 'interfaces',
'endpoints', 'roles', 'transformations'])
)
self.assertEqual(scheme['version'], '1.1')
self.assertEqual(scheme['provider'], 'lnx')
self.assertEqual(
scheme['interfaces'],
{'eth0': {'mtu': 1500,
'vendor_specific': {
'disable_offloading': True}},
'eth1': {}}
)
br_set = set(['br-storage', 'br-mgmt', 'br-fw-admin', 'br-prv'])
role_dict = {'storage': 'br-storage',
'management': 'br-mgmt',
'fw-admin': 'br-fw-admin',
'neutron/private': 'br-prv'}
if is_public:
br_set.update(['br-ex', 'br-floating'])
role_dict.update({'ex': 'br-ex',
'neutron/floating': 'br-floating'})
self.assertEqual(
set(scheme['endpoints'].keys()),
br_set
)
self.check_ep_format(scheme['endpoints'])
self.check_gateways(node_db, scheme, is_public)
self.assertEqual(
scheme['roles'],
role_dict
)
transformations_ = transformations
if not is_public:
# exclude all 'br-ex' and 'br-floating' objects
transformations_ = [
t for t in transformations if all([
t.get('name') not in ('br-ex', 'br-floating'),
t.get('bridge') not in ('br-ex', 'br-floating'),
'br-ex' not in t.get('bridges', []),
'br-floating' not in t.get('bridges', []),
])]
self.assertEqual(
scheme['transformations'],
transformations_
)
def test_vlan_schema(self):
cluster = self.create_env(segment_type='vlan')
self.add_nics_properties(cluster)
serializer = self.create_serializer(cluster)
facts = serializer.serialize(cluster, cluster.nodes)['nodes']
self.check_vlan_schema(facts, [
{'action': 'add-br',
'name': 'br-fw-admin'},
{'action': 'add-br',
'name': 'br-mgmt'},
{'action': 'add-br',
'name': 'br-storage'},
{'action': 'add-br',
'name': 'br-ex'},
{'action': 'add-br',
'name': 'br-floating',
'provider': 'ovs'},
{'action': 'add-patch',
'mtu': 65000,
'bridges': ['br-floating', 'br-ex'],
'provider': 'ovs'},
{'action': 'add-br',
'name': 'br-prv',
'provider': 'ovs'},
{'action': 'add-patch',
'mtu': 65000,
'bridges': ['br-prv', 'br-fw-admin'],
'provider': 'ovs'},
{'action': 'add-port',
'bridge': 'br-fw-admin',
'name': 'eth0'},
{'action': 'add-port',
'bridge': 'br-storage',
'name': 'eth0.102'},
{'action': 'add-port',
'bridge': 'br-mgmt',
'name': 'eth0.101'},
{'action': 'add-port',
'bridge': 'br-ex',
'name': 'eth1'},
])
def test_vlan_schema_with_br_aux(self):
cluster = self.create_env(segment_type='vlan')
self.add_nics_properties(cluster)
# move all networks to first interface and assign private network
# to second one
for node in cluster.nodes:
interfaces = node.interfaces
interfaces[0].assigned_networks_list.extend(
interfaces[1].assigned_networks_list)
private_net = next((
net for net in interfaces[0].assigned_networks_list
if net.name == 'private'))
interfaces[0].assigned_networks_list.remove(private_net)
interfaces[1].assigned_networks_list = [private_net]
self.db.flush()
serializer = self.create_serializer(cluster)
facts = serializer.serialize(cluster, cluster.nodes)['nodes']
self.check_vlan_schema(facts, [
{'action': 'add-br',
'name': 'br-fw-admin'},
{'action': 'add-br',
'name': 'br-mgmt'},
{'action': 'add-br',
'name': 'br-storage'},
{'action': 'add-br',
'name': 'br-ex'},
{'action': 'add-br',
'name': 'br-floating',
'provider': 'ovs'},
{'action': 'add-patch',
'mtu': 65000,
'bridges': ['br-floating', 'br-ex'],
'provider': 'ovs'},
{'action': 'add-br',
'name': 'br-prv',
'provider': 'ovs'},
{'action': 'add-br',
'name': 'br-aux'},
{'action': 'add-patch',
'mtu': 65000,
'bridges': ['br-prv', 'br-aux'],
'provider': 'ovs'},
{'action': 'add-port',
'bridge': 'br-fw-admin',
'name': 'eth0'},
{'action': 'add-port',
'bridge': 'br-ex',
'name': 'eth0'},
{'action': 'add-port',
'bridge': 'br-storage',
'name': 'eth0.102'},
{'action': 'add-port',
'bridge': 'br-mgmt',
'name': 'eth0.101'},
{'action': 'add-port',
'bridge': 'br-aux',
'name': 'eth1'},
])
def test_vlan_with_bond(self):
cluster = self.create_env(segment_type='vlan', ctrl_count=3,
nic_count=3)
for node in cluster.nodes:
self.move_network(node.id, 'storage', 'eth0', 'eth1')
self.env.make_bond_via_api(
'lnx_bond', '', ['eth1', 'eth2'], node.id,
attrs={
'type__': {'value': consts.BOND_TYPES.linux},
'mtu': {'value': {'value': 9000}},
'mode': {'value': {'value': consts.BOND_MODES.balance_rr}}
}
)
serializer = self.create_serializer(cluster)
facts = serializer.serialize(cluster, cluster.nodes)['nodes']
for node in facts:
transformations = [
{'action': 'add-br',
'name': 'br-fw-admin'},
{'action': 'add-br',
'name': 'br-mgmt'},
{'action': 'add-br',
'name': 'br-storage'},
{'action': 'add-br',
'name': 'br-ex'},
{'action': 'add-br',
'name': 'br-floating',
'provider': 'ovs'},
{'action': 'add-patch',
'mtu': 65000,
'bridges': ['br-floating', 'br-ex'],
'provider': 'ovs'},
{'action': 'add-br',
'name': 'br-prv',
'provider': 'ovs'},
{'action': 'add-patch',
'mtu': 65000,
'bridges': ['br-prv', 'br-fw-admin'],
'provider': 'ovs'},
{'action': 'add-port',
'bridge': 'br-fw-admin',
'name': 'eth0'},
{'action': 'add-port',
'bridge': 'br-mgmt',
'name': 'eth0.101'},
{'action': 'add-bond',
'bridge': 'br-ex',
'name': 'lnx_bond',
'mtu': 9000,
'interfaces': ['eth1', 'eth2'],
'bond_properties': {'mode': 'balance-rr'},
'interface_properties': {'mtu': 9000}},
{'action': 'add-port',
'bridge': 'br-storage',
'name': 'lnx_bond.102'},
]
self.assertEqual(
node['network_scheme']['transformations'],
transformations
)
def test_gre_schema(self):
cluster = self.create_env(segment_type='gre')
self.add_nics_properties(cluster)
serializer = self.create_serializer(cluster)
facts = serializer.serialize(cluster, cluster.nodes)['nodes']
for node in facts:
node_db = objects.Node.get_by_uid(node['uid'])
is_public = objects.Node.should_have_public(node_db)
scheme = node['network_scheme']
self.assertEqual(
set(scheme.keys()),
set(['version', 'provider', 'interfaces',
'endpoints', 'roles', 'transformations'])
)
self.assertEqual(scheme['version'], '1.1')
self.assertEqual(scheme['provider'], 'lnx')
self.assertEqual(
scheme['interfaces'],
{'eth0': {'mtu': 1500,
'vendor_specific': {
'disable_offloading': True}},
'eth1': {}}
)
br_set = set(['br-storage', 'br-mgmt', 'br-fw-admin', 'br-mesh'])
role_dict = {'storage': 'br-storage',
'management': 'br-mgmt',
'fw-admin': 'br-fw-admin',
'neutron/mesh': 'br-mesh'}
if is_public:
br_set.update(['br-ex', 'br-floating'])
role_dict.update({'ex': 'br-ex',
'neutron/floating': 'br-floating'})
self.assertEqual(
set(scheme['endpoints'].keys()),
br_set
)
self.check_ep_format(scheme['endpoints'])
self.check_gateways(node_db, scheme, is_public)
self.assertEqual(
scheme['roles'],
role_dict
)
transformations = [
{'action': 'add-br',
'name': 'br-fw-admin'},
{'action': 'add-br',
'name': 'br-mgmt'},
{'action': 'add-br',
'name': 'br-storage'},
{'action': 'add-br',
'name': 'br-ex'},
{'action': 'add-br',
'name': 'br-floating',
'provider': 'ovs'},
{'action': 'add-patch',
'mtu': 65000,
'bridges': ['br-floating', 'br-ex'],
'provider': 'ovs'},
{'action': 'add-br',
'name': 'br-mesh'},
{'action': 'add-port',
'bridge': 'br-fw-admin',
'name': 'eth0'},
{'action': 'add-port',
'bridge': 'br-storage',
'name': 'eth0.102'},
{'action': 'add-port',
'bridge': 'br-mgmt',
'name': 'eth0.101'},
{'action': 'add-port',
'bridge': 'br-mesh',
'name': 'eth0.103'},
{'action': 'add-port',
'bridge': 'br-ex',
'name': 'eth1'},
]
if not is_public:
# exclude all 'br-ex' and 'br-floating' objects
transformations = transformations[:3] + transformations[6:-1]
self.assertEqual(
scheme['transformations'],
transformations
)
def test_gre_with_bond(self):
cluster = self.create_env(segment_type='gre', ctrl_count=3,
nic_count=3)
for node in cluster.nodes:
self.move_network(node.id, 'storage', 'eth0', 'eth1')
self.env.make_bond_via_api(
'lnx_bond', '', ['eth1', 'eth2'], node.id,
attrs={
'mtu': {
'value': {
'value': 9000}},
'mode': {
'value': {
'value': consts.BOND_MODES.l_802_3ad}},
'xmit_hash_policy': {
'value': {
'value': consts.BOND_XMIT_HASH_POLICY.layer2}},
'lacp_rate': {
'value': {
'value': consts.BOND_LACP_RATES.slow}},
'type__': {
'value': consts.BOND_TYPES.linux}
}
)
serializer = self.create_serializer(cluster)
facts = serializer.serialize(cluster, cluster.nodes)['nodes']
for node in facts:
transformations = [
{'action': 'add-br',
'name': 'br-fw-admin'},
{'action': 'add-br',
'name': 'br-mgmt'},
{'action': 'add-br',
'name': 'br-storage'},
{'action': 'add-br',
'name': 'br-ex'},
{'action': 'add-br',
'name': 'br-floating',
'provider': 'ovs'},
{'action': 'add-patch',
'mtu': 65000,
'bridges': ['br-floating', 'br-ex'],
'provider': 'ovs'},
{'action': 'add-br',
'name': 'br-mesh'},
{'action': 'add-port',
'bridge': 'br-fw-admin',
'name': 'eth0'},
{'action': 'add-port',
'bridge': 'br-mgmt',
'name': 'eth0.101'},
{'action': 'add-port', 'bridge': 'br-mesh', 'name':
'eth0.103'},
{'action': 'add-bond',
'bridge': 'br-ex',
'name': 'lnx_bond',
'mtu': 9000,
'interfaces': ['eth1', 'eth2'],
'bond_properties': {'mode': '802.3ad',
'xmit_hash_policy': 'layer2',
'lacp_rate': 'slow'},
'interface_properties': {'mtu': 9000}},
{'action': 'add-port',
'bridge': 'br-storage',
'name': 'lnx_bond.102'},
]
self.assertEqual(
node['network_scheme']['transformations'],
transformations
)
@mock.patch('nailgun.task.task.rpc.cast')
def test_gre_with_multi_groups(self, mocked_rpc):
cluster = self.create_env(segment_type='gre', ctrl_count=3)
resp = self.env.create_node_group()
group_id = resp.json_body['id']
nets = self.env.neutron_networks_get(cluster.id).json_body
nets_w_gw = {'management': '199.99.20.0/24',
'storage': '199.98.20.0/24',
'fuelweb_admin': '199.97.20.0/24',
'private': '199.95.20.0/24',
'public': '199.96.20.0/24'}
for net in nets['networks']:
if net['name'] in nets_w_gw.keys():
if net['group_id'] == group_id:
net['cidr'] = nets_w_gw[net['name']]
if net['meta']['notation'] == 'ip_ranges':
net['ip_ranges'] = [[
str(IPAddress(IPNetwork(net['cidr']).first + 2)),
str(IPAddress(IPNetwork(net['cidr']).first + 126)),
]]
if not net['meta']['use_gateway']:
# IP ranges for networks in default nodegroup must
# be updated as well to exclude gateway address.
# Do not use first address to avoid clashing
# with floating range.
net['ip_ranges'] = [[
str(IPAddress(IPNetwork(net['cidr']).first + 2)),
str(IPAddress(IPNetwork(net['cidr']).first + 254)),
]]
net['meta']['use_gateway'] = True
net['gateway'] = str(
IPAddress(IPNetwork(net['cidr']).first + 1))
resp = self.env.neutron_networks_put(cluster.id, nets)
self.assertEqual(resp.status_code, 200)
self.assertEqual(mocked_rpc.call_count, 1)
self.env.create_nodes_w_interfaces_count(
nodes_count=3,
if_count=2,
roles=['compute'],
pending_addition=True,
cluster_id=cluster.id,
group_id=group_id)
objects.Cluster.prepare_for_deployment(cluster)
serializer = self.create_serializer(cluster)
facts = serializer.serialize(cluster, cluster.nodes)['nodes']
for node in facts:
node_db = objects.Node.get_by_uid(node['uid'])
is_public = objects.Node.should_have_public(node_db)
endpoints = node['network_scheme']['endpoints']
br_set = set(['br-storage', 'br-mgmt', 'br-fw-admin', 'br-mesh'])
if is_public:
br_set.add('br-ex')
# floating network won't have routes
self.assertEqual(endpoints['br-floating'], {'IP': 'none'})
endpoints.pop('br-floating')
self.assertEqual(
set(endpoints.keys()),
br_set
)
for name, descr in six.iteritems(endpoints):
self.assertTrue(set(['IP', 'routes']) <= set(descr.keys()))
self.assertEqual(len(descr['routes']), 1)
for route in descr['routes']:
self.assertEqual(set(['net', 'via']), set(route.keys()))
class TestNovaOrchestratorHASerializer(OrchestratorSerializerTestBase):
env_version = '1111-5.0'
def setUp(self):
super(TestNovaOrchestratorHASerializer, self).setUp()
self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
objects.Cluster.set_primary_tags(self.cluster, self.cluster.nodes)
def create_env(self, mode):
cluster = self.env.create(
release_kwargs={'version': self.env_version},
cluster_kwargs={
'mode': mode,
'net_provider': consts.CLUSTER_NET_PROVIDERS.nova_network},
nodes_kwargs=[
{'roles': ['controller'], 'pending_addition': True},
{'roles': ['controller'], 'pending_addition': True},
{'roles': ['controller', 'cinder'], 'pending_addition': True},
{'roles': ['compute', 'cinder'], 'pending_addition': True},
{'roles': ['compute'], 'pending_addition': True},
{'roles': ['mongo'], 'pending_addition': True},
{'roles': ['cinder'], 'pending_addition': True}])
cluster_db = self.db.query(Cluster).get(cluster['id'])
objects.Cluster.prepare_for_deployment(cluster_db)
return cluster_db
@property
def serializer(self):
self.cluster_mock.release.environment_version = '5.0'
return DeploymentHASerializer(AstuteGraph(self.cluster_mock))
def test_set_deployment_priorities(self):
nodes = [
{'role': 'mongo'},
{'role': 'primary-mongo'},
{'role': 'primary-controller'},
{'role': 'controller'},
{'role': 'controller'},
{'role': 'ceph-osd'}
]
self.add_default_params(nodes)
self.serializer.set_deployment_priorities(nodes)
expected_priorities = [
{'role': 'mongo', 'priority': 100},
{'role': 'primary-mongo', 'priority': 200},
{'role': 'primary-controller', 'priority': 300},
{'role': 'controller', 'priority': 400},
{'role': 'controller', 'priority': 500},
{'role': 'ceph-osd', 'priority': 600},
]
self.add_default_params(expected_priorities)
self.assertEqual(expected_priorities, nodes)
def test_set_deployment_priorities_many_cntrls(self):
nodes = [
{'role': 'mongo'},
{'role': 'primary-mongo'},
{'role': 'primary-controller'},
{'role': 'controller'},
{'role': 'controller'},
{'role': 'controller'},
{'role': 'controller'},
{'role': 'controller'},
{'role': 'controller'},
{'role': 'controller'},
{'role': 'controller'},
{'role': 'ceph-osd'}
]
self.add_default_params(nodes)
self.serializer.set_deployment_priorities(nodes)
expected_priorities = [
{'role': 'mongo', 'priority': 100},
{'role': 'primary-mongo', 'priority': 200},
{'role': 'primary-controller', 'priority': 300},
{'role': 'controller', 'priority': 400},
{'role': 'controller', 'priority': 500},
{'role': 'controller', 'priority': 600},
{'role': 'controller', 'priority': 700},
{'role': 'controller', 'priority': 800},
{'role': 'controller', 'priority': 900},
{'role': 'controller', 'priority': 1000},
{'role': 'controller', 'priority': 1100},
{'role': 'ceph-osd', 'priority': 1200}
]
self.add_default_params(expected_priorities)
self.assertEqual(expected_priorities, nodes)
def test_set_critital_node(self):
serialized_nodes = self.serializer.serialize_nodes(self.cluster.nodes)
expected_ciritial_roles = [
{'fail_if_error': True, 'role': 'primary-controller'},
{'fail_if_error': True, 'role': 'controller'},
{'fail_if_error': False, 'role': 'cinder'},
{'fail_if_error': True, 'role': 'controller'},
{'fail_if_error': False, 'role': 'cinder'},
{'fail_if_error': False, 'role': 'compute'},
{'fail_if_error': False, 'role': 'compute'},
{'fail_if_error': True, 'role': 'primary-mongo'},
{'fail_if_error': False, 'role': 'cinder'}
]
self.assertItemsEqual(
expected_ciritial_roles,
[
{'role': n['role'], 'fail_if_error': n['fail_if_error']}
for n in serialized_nodes
]
)
def test_set_primary_controller_priority_not_depend_on_nodes_order(self):
controllers = filter(lambda n: 'controller' in n.roles, self.env.nodes)
expected_primary_controller = sorted(
controllers, key=attrgetter('id'))[0]
reverse_sorted_controllers = sorted(
controllers, key=attrgetter('id'), reverse=True)
result_nodes = self.serializer.serialize(
self.cluster, reverse_sorted_controllers)['nodes']
high_priority = sorted(result_nodes, key=itemgetter('priority'))[0]
self.assertEqual(high_priority['role'], 'primary-controller')
self.assertEqual(
int(high_priority['uid']),
expected_primary_controller.id)
def test_node_list(self):
serialized_nodes = self.serializer.node_list(self.cluster.nodes)
for node in serialized_nodes:
# Each node has swift_zone
self.assertEqual(node['swift_zone'], node['uid'])
def test_get_common_attrs(self):
attrs = self.serializer.get_common_attrs(self.cluster)
# vips
self.assertEqual(attrs['management_vip'], '192.168.0.8')
self.assertEqual(attrs['public_vip'], '172.16.0.9')
# last_contrller
controllers = self.get_controllers(self.cluster.id)
self.assertEqual(attrs['last_controller'],
'node-%d' % controllers[-1].id)
# primary_controller
controllers = self.filter_by_role(attrs['nodes'], 'primary-controller')
self.assertEqual(controllers[0]['role'], 'primary-controller')
# primary_mongo
mongo_nodes = self.filter_by_role(attrs['nodes'], 'primary-mongo')
self.assertEqual(mongo_nodes[-1]['role'], 'primary-mongo')
# mountpoints and mp attrs
self.assertEqual(
attrs['mp'],
[{'point': '1', 'weight': '1'},
{'point': '2', 'weight': '2'}])
class TestNovaOrchestratorHASerializer51(TestNovaOrchestratorHASerializer):
env_version = '1111-5.1'
@property
def serializer(self):
self.cluster_mock.release.environment_version = '5.1'
return DeploymentHASerializer51(AstuteGraph(self.cluster_mock))
def test_set_deployment_priorities(self):
nodes = [
{'role': 'mongo'},
{'role': 'primary-mongo'},
{'role': 'primary-controller'},
{'role': 'controller'},
{'role': 'controller'},
{'role': 'ceph-osd'}
]
self.add_default_params(nodes)
self.serializer.set_deployment_priorities(nodes)
expected_priorities = [
{'role': 'mongo', 'priority': 100},
{'role': 'primary-mongo', 'priority': 200},
{'role': 'primary-controller', 'priority': 300},
{'role': 'controller', 'priority': 400},
{'role': 'controller', 'priority': 400},
{'role': 'ceph-osd', 'priority': 500},
]
self.add_default_params(expected_priorities)
self.assertEqual(expected_priorities, nodes)
def test_set_deployment_priorities_many_cntrls(self):
nodes = [
{'role': 'mongo'},
{'role': 'primary-mongo'},
{'role': 'primary-controller'},
{'role': 'controller'},
{'role': 'controller'},
{'role': 'controller'},
{'role': 'controller'},
{'role': 'controller'},
{'role': 'controller'},
{'role': 'controller'},
{'role': 'controller'},
{'role': 'ceph-osd'}
]
self.add_default_params(nodes)
self.serializer.set_deployment_priorities(nodes)
expected_priorities = [
{'role': 'mongo', 'priority': 100},
{'role': 'primary-mongo', 'priority': 200},
{'role': 'primary-controller', 'priority': 300},
{'role': 'controller', 'priority': 400},
{'role': 'controller', 'priority': 400},
{'role': 'controller', 'priority': 400},
{'role': 'controller', 'priority': 400},
{'role': 'controller', 'priority': 400},
{'role': 'controller', 'priority': 400},
{'role': 'controller', 'priority': 500},
{'role': 'controller', 'priority': 500},
{'role': 'ceph-osd', 'priority': 600}
]
self.add_default_params(expected_priorities)
self.assertEqual(expected_priorities, nodes)
# TODO(awoodward): multinode deprecation: probably has duplicates
class TestNeutronOrchestratorSerializer(OrchestratorSerializerTestBase):
new_env_release_version = '1111-6.0'
def setUp(self):
super(TestNeutronOrchestratorSerializer, self).setUp()
self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
objects.Cluster.set_primary_tags(self.cluster, self.cluster.nodes)
def create_env(self, mode, segment_type='vlan'):
release_kwargs = {}
if self.new_env_release_version:
release_kwargs['version'] = self.new_env_release_version
# unique name is required as some tests create releases with
# the same version
release_kwargs['name'] = \
self.new_env_release_version + segment_type
cluster = self.env.create(
release_kwargs=release_kwargs,
cluster_kwargs={
'mode': mode,
'net_provider': 'neutron',
'net_segment_type': segment_type
},
nodes_kwargs=[
{'roles': ['controller', 'cinder'], 'pending_addition': True},
{'roles': ['compute', 'cinder'], 'pending_addition': True},
{'roles': ['compute'], 'pending_addition': True},
{'roles': [], 'pending_roles': ['cinder'],
'pending_addition': True}])
cluster_db = self.db.query(Cluster).get(cluster['id'])
objects.Cluster.prepare_for_deployment(cluster_db)
return cluster_db
def serialize_env_w_version(self, version):
self.new_env_release_version = version
cluster = self.create_env(mode=consts.CLUSTER_MODES.ha_compact)
serializer = self.create_serializer(cluster)
return serializer.serialize(cluster, cluster.nodes)
def assert_roles_flattened(self, nodes):
self.assertEqual(len(nodes), 6)
self.assert_nodes_with_role(nodes, 'controller', 1)
self.assert_nodes_with_role(nodes, 'compute', 2)
self.assert_nodes_with_role(nodes, 'cinder', 3)
def set_assign_public_to_all_nodes(self, cluster_db, value):
attrs = copy.deepcopy(cluster_db.attributes.editable)
attrs['public_network_assignment']['assign_to_all_nodes']['value'] = \
value
resp = self.app.patch(
reverse(
'ClusterAttributesHandler',
kwargs={'cluster_id': cluster_db.id}),
params=jsonutils.dumps({'editable': attrs}),
headers=self.default_headers
)
self.assertEqual(200, resp.status_code)
self.assertEqual(
attrs['public_network_assignment']['assign_to_all_nodes']['value'],
value
)
def test_serialize_nodes(self):
serialized_nodes = self.serializer.serialize_nodes(self.cluster.nodes)
self.assert_roles_flattened(serialized_nodes)
# Each not should be same as result of
# serialize_node function
for serialized_node in serialized_nodes:
node_db = self.db.query(Node).get(int(serialized_node['uid']))
expected_node = self.serializer.serialize_node(
node_db, serialized_node['role']
)
self.assertEqual(serialized_node, expected_node)
def test_neutron_vlan_ids_tag_present_on_6_0_env(self):
serialized = self.serialize_env_w_version('2014.2-6.0')
for node in serialized['nodes']:
for item in node['network_scheme']['transformations']:
if 'tags' in item:
self.assertEqual(item['tags'], item['vlan_ids'])
def check_5x_60_neutron_attrs(self, version):
common_attrs = self.serialize_env_w_version(version)['common']
self.assertEqual(
{
"network_type": "local",
"segment_id": None,
"router_ext": True,
"physnet": None
},
common_attrs['quantum_settings']['predefined_networks'][
'admin_floating_net']['L2']
)
self.assertFalse(
'physnet1' in common_attrs['quantum_settings']['L2']['phys_nets']
)
def test_serialize_neutron_attrs_on_6_0_env(self):
self.check_5x_60_neutron_attrs("2014.2-6.0")
def test_serialize_neutron_attrs_on_5_1_env(self):
self.check_5x_60_neutron_attrs("2014.1.1-5.1")
def check_50x_neutron_attrs(self, version):
common_attrs = self.serialize_env_w_version(version)['common']
self.assertEqual(
{
"network_type": "flat",
"segment_id": None,
"router_ext": True,
"physnet": "physnet1"
},
common_attrs['quantum_settings']['predefined_networks'][
'admin_floating_net']['L2']
)
self.assertEqual(
{
"bridge": "br-ex",
"vlan_range": None
},
common_attrs['quantum_settings']['L2']['phys_nets']['physnet1']
)
def test_serialize_neutron_attrs_on_5_0_2_env(self):
self.check_50x_neutron_attrs("2014.1.1-5.0.2")
def test_serialize_neutron_attrs_on_5_0_1_env(self):
self.check_50x_neutron_attrs("2014.1.1-5.0.1")
def test_serialize_neutron_attrs_on_5_0_env(self):
self.check_50x_neutron_attrs("2014.1")
def test_serialize_node(self):
node = self.env.create_node(
api=True, cluster_id=self.cluster.id, pending_addition=True)
objects.Cluster.prepare_for_deployment(self.cluster)
node_db = self.db.query(Node).get(node['id'])
serialized_data = self.serializer.serialize_node(
node_db, 'controller'
)
self.assertEqual(serialized_data['role'], 'controller')
self.assertEqual(serialized_data['uid'], str(node_db.id))
self.assertEqual(serialized_data['status'], node_db.status)
self.assertEqual(serialized_data['online'], node_db.online)
self.assertEqual(serialized_data['fqdn'],
'%s.%s' % (node_db.hostname, settings.DNS_DOMAIN))
def test_node_list(self):
assign_public_options = (False, True)
for assign in assign_public_options:
self.set_assign_public_to_all_nodes(self.cluster, assign)
# Clear IPs
for ip in self.db.query(models.IPAddr):
self.db.delete(ip)
self.db.flush()
objects.Cluster.prepare_for_deployment(self.cluster)
node_list = self.serializer.get_common_attrs(self.cluster)['nodes']
roles_w_public_count = 0
# Check right nodes count with right roles
self.assert_roles_flattened(node_list)
# Check common attrs
for node in node_list:
node_db = self.db.query(Node).get(int(node['uid']))
is_public = objects.Node.should_have_public(node_db)
if is_public:
self.assertEqual(node['public_netmask'], '255.255.255.0')
roles_w_public_count += 1
else:
self.assertFalse('public_netmask' in node)
self.assertEqual(node['internal_netmask'], '255.255.255.0')
self.assertEqual(node['storage_netmask'], '255.255.255.0')
self.assertEqual(node['uid'], str(node_db.id))
self.assertEqual(node['name'], '%s' % node_db.hostname)
self.assertEqual(
node['fqdn'],
'%s.%s' % (node_db.hostname, settings.DNS_DOMAIN))
# We have 6 roles on 4 nodes summarily.
# Only 1 node w 2 roles (controller+cinder) will have public
# when 'assign_to_all_nodes' option is switched off
self.assertEqual(roles_w_public_count, 6 if assign else 2)
# Check uncommon attrs
node_uids = sorted(set([int(n['uid']) for n in node_list]))
man_ip = [str(ip) for ip in IPRange('192.168.0.1', '192.168.0.4')]
pub_ip = [str(ip) for ip in IPRange('172.16.0.2', '172.16.0.5')]
sto_ip = [str(ip) for ip in IPRange('192.168.1.1', '192.168.1.4')]
expected_list = [
{'roles': ['controller', 'cinder']},
{'roles': ['compute', 'cinder']},
{'roles': ['compute']},
{'roles': ['cinder']}]
for i in range(len(expected_list)):
expected_list[i]['attrs'] = {'uid': str(node_uids[i])}
if assign:
expected_list[i]['attrs']['public_address'] = pub_ip[i]
if not assign:
expected_list[0]['attrs']['public_address'] = pub_ip[0]
# Check if ips are unique for node and
# they are the same for all nodes roles
used_man_ip, used_pub_ip, used_sto_ip = [], [], []
for expected in expected_list:
attrs = expected['attrs']
ref_node = self.filter_by_uid(node_list, attrs['uid'])[0]
is_public = objects.Node.should_have_public(
objects.Node.get_by_mac_or_uid(node_uid=attrs['uid']))
self.assertTrue(ref_node['internal_address'] in man_ip)
self.assertTrue(ref_node['storage_address'] in sto_ip)
self.assertFalse(ref_node['internal_address'] in used_man_ip)
self.assertFalse(ref_node['storage_address'] in used_sto_ip)
used_man_ip.append(ref_node['internal_address'])
used_sto_ip.append(ref_node['storage_address'])
# Check if pubclic ip field exists
if is_public:
self.assertTrue(ref_node['public_address'] in pub_ip)
self.assertFalse(ref_node['public_address'] in used_pub_ip)
used_pub_ip.append(ref_node['public_address'])
for role in expected['roles']:
nodes = self.filter_by_role(node_list, role)
node = self.filter_by_uid(nodes, attrs['uid'])[0]
if is_public:
self.assertEqual(node['public_address'],
ref_node['public_address'])
else:
self.assertFalse('public_address' in node)
self.assertEqual(node['storage_address'],
ref_node['storage_address'])
self.assertEqual(node['internal_address'],
ref_node['internal_address'])
def test_public_serialization_for_different_roles(self):
assign_public_options = (False, True)
for assign in assign_public_options:
self.set_assign_public_to_all_nodes(self.cluster, assign)
objects.Cluster.prepare_for_deployment(self.cluster)
serialized = self.serializer.serialize(self.cluster,
self.cluster.nodes)
for node_attrs in serialized['common']['nodes']:
is_public_for_role = objects.Node.should_have_public(
objects.Node.get_by_mac_or_uid(
node_uid=int(node_attrs['uid'])))
self.assertEqual('public_address' in node_attrs,
is_public_for_role)
self.assertEqual('public_netmask' in node_attrs,
is_public_for_role)
need_public_nodes_count = set()
for node in serialized['nodes']:
node_db = self.db.query(Node).get(int(node['uid']))
is_public = objects.Node.should_have_public(node_db)
if is_public:
need_public_nodes_count.add(int(node['uid']))
net_man = objects.Cluster.get_network_manager(node_db.cluster)
self.assertEqual(
net_man.get_ip_by_network_name(
node_db, 'public') is not None,
is_public
)
self.assertEqual(
{
'action': 'add-br',
'name': 'br-ex'
} in node['network_scheme']['transformations'],
is_public
)
self.assertEqual(
{
'action': 'add-patch',
'bridges': ['br-eth1', 'br-ex'],
'trunks': [0]
} in node['network_scheme']['transformations'],
is_public
)
self.assertEqual(
'ex' in node['network_scheme']['roles'],
is_public
)
self.assertEqual(
'br-ex' in node['network_scheme']['endpoints'],
is_public
)
self.assertEqual(len(need_public_nodes_count), 4 if assign else 1)
def test_neutron_l3_gateway(self):
cluster = self.create_env(consts.CLUSTER_MODES.ha_compact, 'gre')
test_gateway = "192.168.111.255"
public_ng = self.db.query(NetworkGroup).filter(
NetworkGroup.name == 'public'
).filter(
NetworkGroup.group_id ==
objects.Cluster.get_default_group(cluster).id
).first()
public_ng.gateway = test_gateway
self.db.add(public_ng)
self.db.commit()
serialized = self.serializer.serialize(cluster, cluster.nodes)
common_attrs = serialized['common']
pd_nets = common_attrs["quantum_settings"]["predefined_networks"]
self.assertEqual(
pd_nets["admin_floating_net"]["L3"]["gateway"],
test_gateway
)
@mock.patch('nailgun.rpc.cast')
def test_neutron_l3_floating_w_multiple_node_groups(self, _):
self.new_env_release_version = '1111-8.0'
ng2_networks = {
'public': {'cidr': '199.10.0.0/24',
'ip_ranges': [['199.10.0.5', '199.10.0.55']],
'gateway': '199.10.0.1'},
'management': {'cidr': '199.10.1.0/24',
'gateway': '199.10.1.1'},
'storage': {'cidr': '199.10.2.0/24',
'gateway': '199.10.2.1'},
'fuelweb_admin': {'cidr': '199.11.0.0/24',
'ip_ranges': [['199.11.0.5', '199.11.0.55']],
'gateway': '199.11.0.1'}
}
cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
ng2 = self.env.create_node_group(api=False, cluster_id=cluster.id)
netw_ids = [net.id for net in ng2.networks]
netconfig = self.env.neutron_networks_get(cluster.id).json_body
for network in netconfig['networks']:
if network['id'] in netw_ids and network['name'] in ng2_networks:
for pkey, pval in six.iteritems(ng2_networks[network['name']]):
network[pkey] = pval
network['meta']['use_gateway'] = True
elif network['meta']['notation'] and not network['gateway']:
cidr = IPNetwork(network['cidr'])
network['gateway'] = six.text_type(IPAddress(cidr.first))
network['meta']['use_gateway'] = True
netconfig['networking_parameters']['floating_ranges'] = \
[['199.10.0.77', '199.10.0.177']]
resp = self.env.neutron_networks_put(cluster.id, netconfig)
self.assertEqual(resp.status_code, 200)
objects.Cluster.prepare_for_deployment(cluster)
serialized = self.serializer.serialize(cluster, cluster.nodes)
common_attrs = serialized['common']
pd_nets = common_attrs["quantum_settings"]["predefined_networks"]
self.assertEqual(
pd_nets["admin_floating_net"]["L3"]["subnet"],
ng2_networks['public']['cidr']
)
self.assertEqual(
pd_nets["admin_floating_net"]["L3"]["gateway"],
ng2_networks['public']['gateway']
)
self.assertEqual(
pd_nets["admin_floating_net"]["L3"]["floating"],
'199.10.0.77:199.10.0.177'
)
def test_gre_segmentation(self):
cluster = self.create_env(consts.CLUSTER_MODES.ha_compact, 'gre')
serialized = self.serializer.serialize(cluster, cluster.nodes)
common_attrs = serialized['common']
self.assertEqual(
common_attrs['quantum_settings']['L2']['segmentation_type'], 'gre')
for fact in serialized['nodes']:
self.assertEqual(
'br-prv' in fact['network_scheme']['endpoints'], False)
self.assertEqual(
'private' in (fact['network_scheme']['roles']), False)
def test_tun_segmentation(self):
self.new_env_release_version = 'liberty-8.0'
cluster = self.create_env(consts.CLUSTER_MODES.ha_compact, 'tun')
serialized = self.serializer.serialize(cluster, cluster.nodes)
common_attrs = serialized['common']
facts = serialized['nodes']
self.assertEqual(
common_attrs['quantum_settings']['L2']['segmentation_type'], 'tun')
for fact in facts:
self.assertNotIn(
'br-prv', fact['network_scheme']['endpoints'])
self.assertNotIn(
'private', fact['network_scheme']['roles'])
def test_gw_added_but_default_gw_is_ex_or_admin(self):
cluster = self.cluster
networks = objects.Cluster.get_default_group(cluster).networks
for net in networks:
if net.name in ('storage', 'management'):
net.gateway = str(IPNetwork(net["cidr"]).cidr[1])
self.db.flush()
objects.Cluster.prepare_for_deployment(cluster)
serializer = self.create_serializer(cluster)
facts = serializer.serialize(cluster, cluster.nodes)['nodes']
for fact in facts:
ep = fact['network_scheme']['endpoints']
if 'br-ex' in ep:
self.assertNotIn('default_gateway', ep['br-fw-admin'])
self.assertIn('gateway', ep['br-ex'])
self.assertIn('default_gateway', ep['br-ex'])
self.assertTrue(ep['br-ex']['default_gateway'])
else:
self.assertIn('gateway', ep['br-fw-admin'])
self.assertIn('default_gateway', ep['br-fw-admin'])
self.assertTrue(ep['br-fw-admin']['default_gateway'])
self.assertIn('gateway', ep['br-storage'])
self.assertIn('gateway', ep['br-mgmt'])
class TestVlanSplinters(OrchestratorSerializerTestBase):
env_version = '1111-6.0'
@property
def vlan_splinters_meta(self):
meta = """
vlan_splinters:
metadata:
toggleable: true
enabled: false
label: "VLAN Splinters"
weight: 50
restrictions:
- condition: "cluster:net_provider != 'neutron'"
action: "hide"
vswitch:
value: "disabled"
label: "Open VSwitch VLAN Splinters feature"
weight: 55
type: "radio"
values:
- data: "soft"
label: "Enable OVS VLAN splinters soft trunks workaround"
description: "Configure OVS to use VLAN splinters workaround
with soft trunk detection. This may resolve issues that
might be encountered when using VLAN tags with OVS and
Neutron on Kernels <3.3 (CentOS)"
- data: "hard"
label: "Enable OVS VLAN splinters hard trunks workaround"
description: "Configure OVS to use VLAN splinters workaround
with hard trunk allocation. Offers similar effect as soft
trunks workaround, but forces each trunk to be predefined.
This may work better than soft trunks especially if you
still see network problems using soft trunks"
- data: "kernel_lt"
label: "EXPERIMENTAL: Use Fedora longterm kernel"
description: "Install the Fedora 3.10 longterm kernel instead
of the default 2.6.32 kernel. This should remove any need
for VLAN Splinters workarounds as the 3.10 kernel has better
support for OVS VLANs. This kernel may not work with all
hardware platforms, use caution."
"""
return yaml.load(meta)
def _create_cluster_for_vlan_splinters(self, segment_type='gre'):
meta = {
'interfaces': [
{'name': 'eth0', 'mac': self.env.generate_random_mac()},
{'name': 'eth1', 'mac': self.env.generate_random_mac()},
{'name': 'eth2', 'mac': self.env.generate_random_mac()},
{'name': 'eth3', 'mac': self.env.generate_random_mac()},
{'name': 'eth4', 'mac': self.env.generate_random_mac()}
]
}
cluster = self.env.create(
release_kwargs={'version': self.env_version},
cluster_kwargs={
'net_provider': 'neutron',
'net_segment_type': segment_type,
'editable_attributes': self.vlan_splinters_meta
},
nodes_kwargs=[
{'roles': ['controller'], 'pending_addition': True,
'meta': meta}
]
)
cluster_db = self.db.query(Cluster).get(cluster['id'])
objects.Cluster.prepare_for_deployment(cluster_db)
return cluster_db
def test_vlan_splinters_disabled(self):
cluster = self._create_cluster_for_vlan_splinters()
cluster_id = cluster.id
editable_attrs = copy.deepcopy(cluster.attributes.editable)
# Remove 'vlan_splinters' attribute and check results.
editable_attrs.pop('vlan_splinters', None)
cluster.attributes.editable = editable_attrs
self.db.commit()
cluster = self.db.query(Cluster).get(cluster_id)
self.assertNotIn('vlan_splinters', editable_attrs)
node = self.serializer.serialize(cluster, cluster.nodes)['nodes'][0]
interfaces = node['network_scheme']['interfaces']
for iface_attrs in interfaces.itervalues():
self.assertIn('L2', iface_attrs)
L2_attrs = iface_attrs['L2']
self.assertIn('vlan_splinters', L2_attrs)
self.assertEqual(L2_attrs['vlan_splinters'], 'off')
self.assertNotIn('trunks', L2_attrs)
# Set 'vlan_splinters' to 'some_text' and check results.
editable_attrs = copy.deepcopy(cluster.attributes.editable)
editable_attrs['vlan_splinters'] = {'vswitch': {'value': 'some_text'}}
editable_attrs['vlan_splinters']['metadata'] = {'enabled': True}
cluster.attributes.editable = editable_attrs
self.db.commit()
cluster = self.db.query(Cluster).get(cluster_id)
editable_attrs = copy.deepcopy(cluster.attributes.editable)
self.assertEqual(editable_attrs['vlan_splinters']['vswitch']['value'],
'some_text')
node = self.serializer.serialize(cluster, cluster.nodes)['nodes'][0]
interfaces = node['network_scheme']['interfaces']
for iface_attrs in interfaces.itervalues():
self.assertIn('L2', iface_attrs)
L2_attrs = iface_attrs['L2']
self.assertNotIn('vlan_splinters', L2_attrs)
self.assertNotIn('trunks', L2_attrs)
# Set 'vlan_splinters' to 'disabled' and check results.
editable_attrs['vlan_splinters']['metadata']['enabled'] = False
cluster.attributes.editable = editable_attrs
self.db.commit()
cluster = self.db.query(Cluster).get(cluster_id)
editable_attrs = cluster.attributes.editable
self.assertEqual(
editable_attrs['vlan_splinters']['metadata']['enabled'],
False
)
node = self.serializer.serialize(cluster, cluster.nodes)['nodes'][0]
interfaces = node['network_scheme']['interfaces']
for iface_attrs in interfaces.itervalues():
self.assertIn('L2', iface_attrs)
L2_attrs = iface_attrs['L2']
self.assertIn('vlan_splinters', L2_attrs)
self.assertEqual(L2_attrs['vlan_splinters'], 'off')
self.assertNotIn('trunks', L2_attrs)
def test_kernel_lt_vlan_splinters(self):
cluster = self._create_cluster_for_vlan_splinters()
cluster_id = cluster.id
editable_attrs = copy.deepcopy(cluster.attributes.editable)
# value of kernel-ml should end up with vlan_splinters = off
editable_attrs['vlan_splinters']['metadata']['enabled'] = True
editable_attrs['vlan_splinters']['vswitch']['value'] = 'kernel_lt'
cluster.attributes.editable = editable_attrs
self.db.commit()
cluster = self.db.query(Cluster).get(cluster_id)
editable_attrs = cluster.attributes.editable
self.assertEqual(editable_attrs['vlan_splinters']['vswitch']['value'],
'kernel_lt')
node = self.serializer.serialize(cluster, cluster.nodes)['nodes'][0]
interfaces = node['network_scheme']['interfaces']
for iface_attrs in interfaces.itervalues():
self.assertIn('L2', iface_attrs)
L2_attrs = iface_attrs['L2']
self.assertIn('vlan_splinters', L2_attrs)
self.assertEqual(L2_attrs['vlan_splinters'], 'off')
self.assertNotIn('trunks', L2_attrs)
def test_hard_vlan_splinters_in_gre(self):
cluster = self._create_cluster_for_vlan_splinters('gre')
editable_attrs = copy.deepcopy(cluster.attributes.editable)
editable_attrs['vlan_splinters']['metadata']['enabled'] = True
editable_attrs['vlan_splinters']['vswitch']['value'] = 'hard'
cluster.attributes.editable = editable_attrs
self.db.commit()
vlan_set = set(
[ng.vlan_start for ng in cluster.network_groups if ng.vlan_start]
)
node = self.serializer.serialize(cluster, cluster.nodes)['nodes'][0]
interfaces = node['network_scheme']['interfaces']
for iface_attrs in interfaces.itervalues():
self.assertIn('L2', iface_attrs)
L2_attrs = iface_attrs['L2']
self.assertIn('vlan_splinters', L2_attrs)
self.assertEqual(L2_attrs['vlan_splinters'], 'auto')
self.assertIn('trunks', L2_attrs)
self.assertIn(0, L2_attrs['trunks'])
for n in L2_attrs['trunks']:
if n:
vlan_set.remove(n)
self.assertEqual(len(vlan_set), 0)
def test_hard_vlan_splinters_in_vlan(self):
cluster = self._create_cluster_for_vlan_splinters('vlan')
editable_attrs = copy.deepcopy(cluster.attributes.editable)
editable_attrs['vlan_splinters']['metadata']['enabled'] = True
editable_attrs['vlan_splinters']['vswitch']['value'] = 'hard'
cluster.attributes.editable = editable_attrs
self.db.commit()
vlan_set = set(
[ng.vlan_start for ng in cluster.network_groups if ng.vlan_start]
)
private_vlan_range = cluster.network_config["vlan_range"]
vlan_set.update(range(*private_vlan_range))
vlan_set.add(private_vlan_range[1])
node = self.serializer.serialize(cluster, cluster.nodes)['nodes'][0]
interfaces = node['network_scheme']['interfaces']
for iface_attrs in interfaces.itervalues():
self.assertIn('L2', iface_attrs)
L2_attrs = iface_attrs['L2']
self.assertIn('vlan_splinters', L2_attrs)
self.assertEqual(L2_attrs['vlan_splinters'], 'auto')
self.assertIn('trunks', L2_attrs)
self.assertIn(0, L2_attrs['trunks'])
for n in L2_attrs['trunks']:
if n:
vlan_set.remove(n)
self.assertEqual(len(vlan_set), 0)
def test_soft_vlan_splinters_in_vlan(self):
cluster = self._create_cluster_for_vlan_splinters('vlan')
editable_attrs = copy.deepcopy(cluster.attributes.editable)
editable_attrs['vlan_splinters']['metadata']['enabled'] = True
editable_attrs['vlan_splinters']['vswitch']['value'] = 'soft'
cluster.attributes.editable = editable_attrs
self.db.commit()
node = self.serializer.serialize(cluster, cluster.nodes)['nodes'][0]
interfaces = node['network_scheme']['interfaces']
for iface_attrs in interfaces.itervalues():
self.assertIn('L2', iface_attrs)
L2_attrs = iface_attrs['L2']
self.assertIn('vlan_splinters', L2_attrs)
self.assertEqual(L2_attrs['vlan_splinters'], 'auto')
self.assertIn('trunks', L2_attrs)
self.assertEqual(L2_attrs['trunks'], [0])
class TestNeutronOrchestratorHASerializer(OrchestratorSerializerTestBase):
env_version = '1111-5.0'
def setUp(self):
super(TestNeutronOrchestratorHASerializer, self).setUp()
self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
objects.Cluster.set_primary_tags(self.cluster, self.cluster.nodes)
def create_env(self, mode):
cluster = self.env.create(
api=True,
release_kwargs={'version': self.env_version},
cluster_kwargs={
'mode': mode,
'net_provider': 'neutron',
'net_segment_type': 'vlan'
},
nodes_kwargs=[
{'roles': ['controller'], 'pending_addition': True},
{'roles': ['controller'], 'pending_addition': True},
{'roles': ['controller', 'cinder'], 'pending_addition': True},
{'roles': ['compute', 'cinder'], 'pending_addition': True},
{'roles': ['compute'], 'pending_addition': True},
{'roles': ['cinder'], 'pending_addition': True}
]
)
cluster_db = self.db.query(Cluster).get(cluster['id'])
objects.Cluster.prepare_for_deployment(cluster_db)
return cluster_db
@property
def serializer(self):
self.cluster_mock.release.environment_version = '5.0'
return DeploymentHASerializer(AstuteGraph(self.cluster_mock))
def test_node_list(self):
serialized_nodes = self.serializer.node_list(self.cluster.nodes)
for node in serialized_nodes:
# Each node has swift_zone
self.assertEqual(node['swift_zone'], node['uid'])
def test_get_common_attrs(self):
attrs = self.serializer.get_common_attrs(self.cluster)
# vips
self.assertEqual(attrs['management_vip'], '192.168.0.7')
self.assertTrue(
re.compile('172.16.0.[1-9]').match(attrs['public_vip']))
# last_contrller
controllers = self.get_controllers(self.cluster.id)
self.assertEqual(attrs['last_controller'],
'node-%d' % controllers[-1].id)
# primary_controller
controllers = self.filter_by_role(attrs['nodes'], 'primary-controller')
self.assertEqual(controllers[0]['role'], 'primary-controller')
# mountpoints and mp attrs
self.assertEqual(
attrs['mp'],
[{'point': '1', 'weight': '1'},
{'point': '2', 'weight': '2'}])
class TestNeutronOrchestratorSerializerBonds(OrchestratorSerializerTestBase):
env_version = '1111-6.0'
def create_release(self):
self.release_id = self.env.create_release(version=self.env_version).id
def create_env(self, nodes_count=2, nic_count=3, segment_type='vlan'):
cluster = self.env.create_cluster(
net_provider='neutron',
net_segment_type=segment_type,
release_id=self.release_id)
self.env.create_nodes_w_interfaces_count(
nodes_count=1,
if_count=nic_count,
roles=['controller', 'cinder'],
pending_addition=True,
cluster_id=cluster['id'])
self.env.create_nodes_w_interfaces_count(
nodes_count=nodes_count - 1,
if_count=nic_count,
roles=['compute'],
pending_addition=True,
cluster_id=cluster['id'])
cluster_db = self.db.query(Cluster).get(cluster['id'])
return cluster_db
def check_add_bond_msg_lacp(self, msg):
expected = {
'action': 'add-bond',
'bridge': 'br-ovsbond0',
'interfaces': ['eth1', 'eth2'],
'name': 'ovsbond0',
'properties': ['lacp=active', 'bond_mode=balance-tcp']
}
self.datadiff(msg, expected, compare_sorted=True)
def check_add_bond_msg_non_lacp(self, msg, mode):
expected = {
'action': 'add-bond',
'bridge': 'br-ovsbond0',
'interfaces': ['eth2', 'eth1'],
'name': 'ovsbond0',
'properties': ['bond_mode={0}'.format(mode)]
}
self.datadiff(msg, expected, compare_sorted=True)
def check_bond_with_mode(self, mode, bond_type):
cluster = self.create_env()
for node in cluster.nodes:
self.env.make_bond_via_api(
'ovsbond0', mode, ['eth1', 'eth2'], node.id,
attrs={'type__': {'value': bond_type}})
facts = self.serialize(cluster)
for node in facts['nodes']:
transforms = node['network_scheme']['transformations']
bonds = filter(lambda t: t['action'] == 'add-bond',
transforms)
self.assertEqual(len(bonds), 1)
if mode == consts.BOND_MODES.lacp_balance_tcp:
self.check_add_bond_msg_lacp(bonds[0])
else:
self.check_add_bond_msg_non_lacp(bonds[0], mode)
def test_bonds_serialization(self):
self.create_release()
from nailgun.extensions.network_manager.validators.network \
import NetAssignmentValidator
ovs_modes = NetAssignmentValidator.get_allowed_modes_for_bond_type(
consts.BOND_TYPES.ovs)
for mode in consts.BOND_MODES:
if mode in ovs_modes:
bond_type = consts.BOND_TYPES.ovs
else:
bond_type = consts.BOND_TYPES.linux
self.check_bond_with_mode(mode, bond_type)
class TestCephOsdImageOrchestratorSerialize(OrchestratorSerializerTestBase):
env_version = '1111-6.0'
def setUp(self):
super(TestCephOsdImageOrchestratorSerialize, self).setUp()
cluster = self.env.create(
release_kwargs={
'version': self.env_version,
'modes': [consts.CLUSTER_MODES.ha_compact,
consts.CLUSTER_MODES.multinode]},
cluster_kwargs={
'mode': consts.CLUSTER_MODES.multinode},
nodes_kwargs=[
{'roles': ['controller', 'ceph-osd']}])
self.app.patch(
reverse(
'ClusterAttributesHandler',
kwargs={'cluster_id': cluster['id']}),
params=jsonutils.dumps({
'editable': {'storage': {'images_ceph': {'value': True}}}}),
headers=self.default_headers)
self.cluster = self.db.query(Cluster).get(cluster['id'])
class TestMongoNodesSerialization(OrchestratorSerializerTestBase):
env_version = '1111-5.0'
def create_env(self):
cluster = self.env.create(
release_kwargs={'version': self.env_version},
cluster_kwargs={
'mode': consts.CLUSTER_MODES.ha_compact,
'network_manager': 'FlatDHCPManager'
},
nodes_kwargs=[
{'roles': ['mongo'], 'pending_addition': True},
{'roles': ['mongo'], 'pending_addition': True},
{'roles': ['mongo'], 'pending_addition': True}
]
)
cluster = self.db.query(Cluster).get(cluster['id'])
objects.Cluster.prepare_for_deployment(cluster)
return cluster
@property
def serializer_ha(self):
self.cluster_mock.release.environment_version = '5.0'
return DeploymentHASerializer(AstuteGraph(self.cluster_mock))
@property
def serializer_mn(self):
self.cluster_mock.release.environment_version = '5.0'
return DeploymentMultinodeSerializer(AstuteGraph(self.cluster_mock))
def test_mongo_roles_equals_in_defferent_modes(self):
cluster = self.create_env()
ha_nodes = self.serializer_ha.serialize_nodes(cluster.nodes)
mn_nodes = self.serializer_mn.serialize_nodes(cluster.nodes)
self.assertEqual(mn_nodes, ha_nodes)
class TestNSXOrchestratorSerializer(OrchestratorSerializerTestBase):
env_version = '1111-6.0'
def setUp(self):
super(TestNSXOrchestratorSerializer, self).setUp()
self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
def create_env(self, mode, segment_type='gre'):
cluster = self.env.create(
release_kwargs={'version': self.env_version},
cluster_kwargs={
'mode': mode,
'net_provider': 'neutron',
'net_segment_type': segment_type
},
nodes_kwargs=[
{'roles': ['controller'], 'pending_addition': True},
{'roles': ['compute'], 'pending_addition': True},
]
)
cluster_db = self.db.query(Cluster).get(cluster['id'])
editable_attrs = copy.deepcopy(cluster_db.attributes.editable)
nsx_attrs = editable_attrs.setdefault('nsx_plugin', {})
nsx_attrs.setdefault('metadata', {})['enabled'] = True
cluster_db.attributes.editable = editable_attrs
self.db.commit()
cluster_db = self.db.query(Cluster).get(cluster['id'])
objects.Cluster.prepare_for_deployment(cluster_db)
return cluster_db
def test_serialize_node(self):
serialized_data = self.serializer.serialize(self.cluster,
self.cluster.nodes)
q_settings = serialized_data['common']['quantum_settings']
self.assertIn('L2', q_settings)
self.assertIn('provider', q_settings['L2'])
self.assertEqual(q_settings['L2']['provider'], 'nsx')
l3_settings = q_settings['L3']
self.assertIn('dhcp_agent', l3_settings)
self.assertIn('enable_isolated_metadata', l3_settings['dhcp_agent'])
self.assertEqual(l3_settings['dhcp_agent']['enable_isolated_metadata'],
True)
self.assertIn('enable_metadata_network', l3_settings['dhcp_agent'])
self.assertEqual(l3_settings['dhcp_agent']['enable_metadata_network'],
True)
class BaseDeploymentSerializer(BaseSerializerTest):
node_name = 'node name'
# Needs to be set in childs
serializer = None
env_version = '2014.2-6.1'
def setUp(self):
super(BaseDeploymentSerializer, self).setUp()
self.common_attrs = mock.MagicMock()
def create_env(self, mode):
if mode == consts.CLUSTER_MODES.multinode:
available_modes = [consts.CLUSTER_MODES.ha_compact,
consts.CLUSTER_MODES.multinode]
else:
available_modes = [consts.CLUSTER_MODES.ha_compact, ]
return self.env.create(
release_kwargs={
'version': self.env_version,
'modes': available_modes,
},
cluster_kwargs={
'mode': mode,
'net_provider': 'neutron',
'net_segment_type': 'gre'},
nodes_kwargs=[
{'roles': ['controller'],
'pending_addition': True,
'name': self.node_name,
}
])
def check_serialize_node(self):
self.assertEqual(
self.serializer.serialize_node(
self.env.nodes[0], 'role'
)['user_node_name'],
self.node_name)
def check_serialize_node_for_node_list(self):
self.assertEqual(
self.serializer.serialize_node_for_node_list(
self.env.nodes[0], 'role')['user_node_name'],
self.node_name)
def check_no_murano_data(self):
glance_properties = self.serializer.generate_test_vm_image_data(
self.env.nodes[0])['test_vm_image']['glance_properties']
self.assertNotIn('murano_image_info', glance_properties)
def check_murano_data(self):
glance_properties = self.serializer.generate_test_vm_image_data(
self.env.nodes[0])['test_vm_image']['glance_properties']
self.assertIn('murano_image_info', glance_properties)
@staticmethod
def _get_serializer(cluster):
serializer_type = get_serializer_for_cluster(cluster)
return serializer_type(AstuteGraph(cluster))
@staticmethod
def _get_nodes_count_in_astute_info(nodes):
"""Count number of node in deployment info for non-LCM serializers
As we are running 7.0 tests against 9.0 environments where
LCM serializer is used we should consider difference in a number
of elements in deployment info.
In case of non-LCM serializer we have separate item in deployment
info for each node-role relationship.
:param nodes: array of cluster nodes
:returns: expected number of elements in deployment info
"""
return len([role for n in nodes for role in n.roles])
@staticmethod
def _handle_facts(facts):
"""Handle deployment facts for non-LCM serializers
This method was introduced to be overloaded for classes where LCM
serialization engine is used and 'master' node info should be
filtered.
:param facts: deployment info produced by non-LCM serializer
:returns: deployment info as it is
"""
return facts
@staticmethod
def _get_plugins_names(plugins):
"""Plugins names for non-LCM serializers
Plugins data in case of legacy serializers consist
of plugins names only.
Could be overloaded by LCM serializers.
:param plugins: array of plugins names
:returns: plugins names as it is
"""
return plugins
class TestDeploymentMultinodeSerializer61(BaseDeploymentSerializer):
def setUp(self):
super(TestDeploymentMultinodeSerializer61, self).setUp()
self.cluster = self.create_env(consts.CLUSTER_MODES.multinode)
objects.Cluster.prepare_for_deployment(self.env.clusters[-1])
self.serializer = DeploymentMultinodeSerializer61(self.cluster)
def test_serialize_node(self):
self.check_serialize_node()
def test_serialize_node_for_node_list(self):
self.check_serialize_node_for_node_list()
def test_glance_properties(self):
self.check_no_murano_data()
class TestDeploymentAttributesSerialization61(BaseDeploymentSerializer):
def setUp(self):
super(TestDeploymentAttributesSerialization61, self).setUp()
self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
objects.Cluster.prepare_for_deployment(self.env.clusters[-1])
self.serializer = DeploymentHASerializer61(self.cluster)
@mock.patch('nailgun.objects.MasterNodeSettings.must_send_stats',
return_value=False)
def test_serialize_workloads_collector_user_opted_out(self, _):
oswl_user = self.serializer.get_common_attrs(
self.cluster
)['workloads_collector']
self.assertEqual(set(oswl_user.keys()),
set(['username',
'enabled',
'password',
'metadata',
'tenant',
'create_user']))
self.assertEqual(oswl_user['username'], 'fuel_stats_user')
self.assertEqual(oswl_user['enabled'], True)
self.assertEqual(len(oswl_user['password']), 24)
self.assertEqual(oswl_user['tenant'], 'services')
self.assertEqual(oswl_user['create_user'], False)
@mock.patch('nailgun.objects.MasterNodeSettings.must_send_stats',
return_value=True)
def test_serialize_workloads_collector_user_opted_in(self, _):
oswl_user = self.serializer.get_common_attrs(
self.cluster
)['workloads_collector']
self.assertEqual(set(oswl_user.keys()),
set(['username',
'enabled',
'password',
'metadata',
'tenant',
'create_user']))
self.assertEqual(oswl_user['username'], 'fuel_stats_user')
self.assertEqual(oswl_user['enabled'], True)
self.assertEqual(len(oswl_user['password']), 24)
self.assertEqual(oswl_user['tenant'], 'services')
self.assertEqual(oswl_user['create_user'], True)
class TestDeploymentHASerializer61(BaseDeploymentSerializer):
def setUp(self):
super(TestDeploymentHASerializer61, self).setUp()
self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
objects.Cluster.prepare_for_deployment(self.env.clusters[-1])
self.serializer = DeploymentHASerializer61(self.cluster)
def check_generate_test_vm_image_data(self):
kvm_img_name = 'TestVM'
kvm_img_disk_format = 'qcow2'
kvm_img_path = '/opt/vm/cirros-x86_64-disk.img'
self.assertEqual(
len(self.serializer.generate_test_vm_image_data(
self.env.nodes[0])['test_vm_image']), 2)
self.assertEqual(
self.serializer.generate_test_vm_image_data(
self.env.nodes[0])['test_vm_image'][1]['img_name'],
kvm_img_name)
self.assertEqual(
self.serializer.generate_test_vm_image_data(
self.env.nodes[0])['test_vm_image'][1]['disk_format'],
kvm_img_disk_format)
self.assertEqual(
self.serializer.generate_test_vm_image_data(
self.env.nodes[0])['test_vm_image'][1]['img_path'],
kvm_img_path)
def test_serialize_node(self):
self.check_serialize_node()
def test_serialize_node_for_node_list(self):
self.check_serialize_node_for_node_list()
def test_glance_properties(self):
self.check_no_murano_data()
class TestSerializeInterfaceDriversData(base.BaseIntegrationTest):
env_version = '2014.2-6.1'
def setUp(self):
super(TestSerializeInterfaceDriversData, self).setUp()
self.common_attrs = mock.MagicMock()
def _create_cluster_for_interfaces(self, driver_mapping={},
bus_mapping={},
segment_type='gre'):
meta = {
'interfaces': [
{'name': 'eth0', 'mac': self.env.generate_random_mac(),
'driver': driver_mapping.get('eth0', 'igb'),
'bus_info': bus_mapping.get('eth0', '0000:05:00.0')},
{'name': 'eth1', 'mac': self.env.generate_random_mac(),
'driver': driver_mapping.get('eth1', 'mlx4_en'),
'bus_info': bus_mapping.get('eth1', '0000:06:00.0')}
]
}
cluster = self.env.create(
release_kwargs={'version': self.env_version},
cluster_kwargs={
'net_provider': 'neutron',
'net_segment_type': segment_type
},
nodes_kwargs=[
{'roles': ['controller'], 'pending_addition': True,
'meta': meta}
]
)
self.serializer = DeploymentHASerializer61(cluster)
cluster_db = self.db.query(Cluster).get(cluster['id'])
objects.Cluster.prepare_for_deployment(cluster_db)
return cluster_db
def test_interface_driver_bus_info(self):
driver_mapping = {'eth0': 'igb',
'eth1': 'eth_ipoib'}
bus_mapping = {'eth0': '0000:01:00.0',
'eth1': 'ib1'}
cluster = \
self._create_cluster_for_interfaces(driver_mapping, bus_mapping)
self.db.commit()
cluster_db = self.db.query(Cluster).get(cluster['id'])
node = self.serializer.serialize_node(
cluster_db.nodes[0], 'controller'
)
interfaces = node['network_scheme']['interfaces']
for iface, iface_attrs in interfaces.items():
self.assertIn('vendor_specific', iface_attrs)
self.assertIn('driver', iface_attrs['vendor_specific'])
self.assertEqual(iface_attrs['vendor_specific']['driver'],
driver_mapping[iface])
self.assertIn('bus_info', iface_attrs['vendor_specific'])
self.assertEqual(iface_attrs['vendor_specific']['bus_info'],
bus_mapping[iface])
def test_interface_mapping(self):
cluster = self._create_cluster_for_interfaces(segment_type='vlan')
network_group = self.db().query(NetworkGroup)
public_vlan = randint(0, 4095)
storage_vlan = randint(0, 4095)
management_vlan = randint(0, 4095)
private_vlan_range = [randint(0, 4095), randint(0, 4095)]
vlan_mapping = {'ex': public_vlan,
'storage': storage_vlan,
'management': management_vlan,
'neutron/private': "%s:%s" % (private_vlan_range[0],
private_vlan_range[1])}
cluster.network_config["vlan_range"] = private_vlan_range
network_group.filter_by(name="storage").update(
{"vlan_start": storage_vlan}, synchronize_session="fetch")
network_group.filter_by(name="management").update(
{"vlan_start": management_vlan}, synchronize_session="fetch")
network_group.filter_by(name="public").update(
{"vlan_start": public_vlan}, synchronize_session="fetch")
self.db.commit()
cluster_db = self.db.query(Cluster).get(cluster['id'])
node = self.serializer.serialize_node(
cluster_db.nodes[0], 'controller'
)
endpoints = node['network_scheme']['endpoints']
net_roles = node['network_scheme']['roles']
for net_role, bridge in net_roles.items():
ep_dict = endpoints[bridge]
if net_role in vlan_mapping.keys():
self.assertIn('vendor_specific', ep_dict.keys())
self.assertIn('phy_interfaces',
ep_dict['vendor_specific'].keys())
self.assertIn('vlans', ep_dict['vendor_specific'].keys())
self.assertEqual(ep_dict['vendor_specific']['vlans'],
vlan_mapping[net_role])
class TestDeploymentHASerializer50(BaseDeploymentSerializer):
env_version = '1111-5.0'
def setUp(self):
super(TestDeploymentHASerializer50, self).setUp()
self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
objects.Cluster.prepare_for_deployment(self.env.clusters[-1])
self.serializer = DeploymentHASerializer50(self.cluster)
def test_glance_properties(self):
self.check_murano_data()
class TestDeploymentMultinodeSerializer50(BaseDeploymentSerializer):
env_version = '1111-5.0'
def setUp(self):
super(TestDeploymentMultinodeSerializer50, self).setUp()
self.cluster = self.create_env(consts.CLUSTER_MODES.multinode)
objects.Cluster.prepare_for_deployment(self.env.clusters[-1])
self.serializer = DeploymentMultinodeSerializer50(self.cluster)
def test_glance_properties(self):
self.check_murano_data()
class TestDeploymentGraphlessSerializers(OrchestratorSerializerTestBase):
env_version = '1111-5.0'
def setUp(self):
super(TestDeploymentGraphlessSerializers, self).setUp()
self.cluster = self.env.create(
release_kwargs={'version': self.env_version},
cluster_kwargs={'api': False},
nodes_kwargs=[
{'roles': ['controller', 'cinder'], 'pending_addition': True},
{'roles': ['compute', 'cinder'], 'pending_addition': True},
{'roles': ['compute'], 'pending_addition': True},
{'roles': [], 'pending_roles': ['cinder'],
'pending_addition': True}]
)
objects.Cluster.set_primary_tags(self.cluster, self.cluster.nodes)
@property
def serializer(self):
self.cluster_mock.release.environment_version = '5.0'
return DeploymentMultinodeSerializer(None)
def test_serialize_cluster(self):
serialized_data = self.serialize(self.cluster)
self.assertGreater(len(serialized_data), 0)
self.assertNotIn('tasks', serialized_data['nodes'][0])
self.assertGreater(len(serialized_data['common']['nodes']), 0)