1606 lines
64 KiB
Python
1606 lines
64 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
|
|
import re
|
|
|
|
from netaddr import IPRange
|
|
|
|
from nailgun.consts import OVS_BOND_MODES
|
|
from nailgun.db.sqlalchemy.models import Cluster
|
|
from nailgun.db.sqlalchemy.models import NetworkGroup
|
|
from nailgun.db.sqlalchemy.models import Node
|
|
from nailgun.openstack.common import jsonutils
|
|
|
|
from nailgun.orchestrator.deployment_serializers import\
|
|
create_serializer
|
|
from nailgun.orchestrator.deployment_serializers import\
|
|
DeploymentHASerializer
|
|
from nailgun.orchestrator.deployment_serializers import\
|
|
DeploymentHASerializer51
|
|
from nailgun.orchestrator.deployment_serializers import\
|
|
DeploymentMultinodeSerializer
|
|
|
|
from nailgun.orchestrator.priority_serializers import\
|
|
PriorityHASerializer50
|
|
from nailgun.orchestrator.priority_serializers import\
|
|
PriorityHASerializer51
|
|
from nailgun.orchestrator.priority_serializers import\
|
|
PriorityHASerializerPatching
|
|
from nailgun.orchestrator.priority_serializers import\
|
|
PriorityMultinodeSerializer50
|
|
|
|
from nailgun.db.sqlalchemy import models
|
|
from nailgun import objects
|
|
|
|
from nailgun.settings import settings
|
|
from nailgun.test.base import BaseIntegrationTest
|
|
from nailgun.test.base import reverse
|
|
from nailgun.volumes import manager
|
|
|
|
|
|
class OrchestratorSerializerTestBase(BaseIntegrationTest):
|
|
"""Class containts helpers."""
|
|
|
|
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.role_list.any(name='controller')).\
|
|
order_by(Node.id)
|
|
|
|
@property
|
|
def serializer(self):
|
|
return DeploymentHASerializer(PriorityHASerializer50())
|
|
|
|
def serialize(self, cluster):
|
|
objects.NodeCollection.prepare_for_deployment(cluster.nodes)
|
|
return self.serializer.serialize(cluster, cluster.nodes)
|
|
|
|
def _make_data_copy(self, data_to_copy):
|
|
'''Sqalchemy doesn't track change on composite attribute
|
|
so we need to create fresh copy of it which will take all
|
|
needed modifications and will be assigned as new value
|
|
for that attribute
|
|
'''
|
|
return copy.deepcopy(data_to_copy)
|
|
|
|
|
|
# TODO(awoodward): multinode deprecation: probably has duplicates
|
|
class TestNovaOrchestratorSerializer(OrchestratorSerializerTestBase):
|
|
|
|
def setUp(self):
|
|
super(TestNovaOrchestratorSerializer, self).setUp()
|
|
self.cluster = self.create_env('ha_compact')
|
|
|
|
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(
|
|
cluster_kwargs={
|
|
'mode': mode,
|
|
'net_manager': network_manager},
|
|
nodes_kwargs=node_args)
|
|
|
|
cluster_db = self.db.query(Cluster).get(cluster['id'])
|
|
objects.NodeCollection.prepare_for_deployment(cluster_db.nodes)
|
|
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.NodeCollection.prepare_for_deployment(self.cluster.nodes)
|
|
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'],
|
|
'node-%d.%s' % (node_db.id, settings.DNS_DOMAIN))
|
|
self.assertEqual(
|
|
serialized_data['glance'],
|
|
{'image_cache_max_size': manager.calc_glance_cache_size(
|
|
node_db.attributes.volumes)})
|
|
|
|
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'], 'node-%d' % node_db.id)
|
|
self.assertEqual(node['fqdn'], 'node-%d.%s' %
|
|
(node_db.id, settings.DNS_DOMAIN))
|
|
|
|
# Check uncommon attrs
|
|
node_uids = sorted(set([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': 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):
|
|
cluster = self.create_env('ha_compact')
|
|
facts = self.serializer.serialize(cluster, cluster.nodes)
|
|
for fact in facts:
|
|
self.assertEqual(
|
|
fact['novanetwork_parameters']['network_manager'],
|
|
'FlatDHCPManager')
|
|
self.assertEqual(
|
|
fact['novanetwork_parameters']['num_networks'], 1)
|
|
self.assertEqual(
|
|
fact['novanetwork_parameters']['network_size'], 65536)
|
|
|
|
def test_vlan_manager(self):
|
|
cluster = self.create_env('ha_compact')
|
|
data = {'networking_parameters': {'net_manager': 'VlanManager'}}
|
|
url = reverse('NovaNetworkConfigurationHandler',
|
|
kwargs={'cluster_id': cluster.id})
|
|
self.app.put(url, jsonutils.dumps(data),
|
|
headers=self.default_headers,
|
|
expect_errors=False)
|
|
facts = self.serializer.serialize(cluster, cluster.nodes)
|
|
|
|
for fact in facts:
|
|
self.assertEqual(fact['vlan_interface'], 'eth0')
|
|
self.assertEqual(fact['fixed_interface'], 'eth0')
|
|
self.assertEqual(
|
|
fact['novanetwork_parameters']['network_manager'],
|
|
'VlanManager')
|
|
self.assertEqual(
|
|
fact['novanetwork_parameters']['num_networks'], 1)
|
|
self.assertEqual(
|
|
fact['novanetwork_parameters']['vlan_start'], 103)
|
|
self.assertEqual(
|
|
fact['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)
|
|
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.orchestrator.deployment_serializers \
|
|
import NovaNetworkDeploymentSerializer
|
|
interfaces = NovaNetworkDeploymentSerializer.\
|
|
configure_interfaces(node_db)
|
|
|
|
expected_interfaces = {
|
|
'lo': {
|
|
'interface': 'lo',
|
|
'ipaddr': ['127.0.0.1/8']
|
|
},
|
|
'eth1': {
|
|
'interface': 'eth1',
|
|
'ipaddr': ['10.20.0.129/24']
|
|
},
|
|
'eth0': {
|
|
'interface': 'eth0',
|
|
'ipaddr': ['172.16.0.2/24',
|
|
'192.168.0.1/24',
|
|
'192.168.1.1/24'],
|
|
'gateway': '172.16.0.1',
|
|
'default_gateway': True
|
|
}
|
|
}
|
|
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'},
|
|
{'role': 'other'}
|
|
]
|
|
serializer = DeploymentMultinodeSerializer(
|
|
PriorityMultinodeSerializer50())
|
|
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},
|
|
{'role': 'other', 'priority': 500}
|
|
]
|
|
self.assertEqual(expected_priorities, nodes)
|
|
|
|
def test_set_critital_node(self):
|
|
nodes = [
|
|
{'role': 'mongo'},
|
|
{'role': 'mongo'},
|
|
{'role': 'primary-mongo'},
|
|
{'role': 'controller'},
|
|
{'role': 'ceph-osd'},
|
|
{'role': 'other'}
|
|
]
|
|
serializer = DeploymentMultinodeSerializer(
|
|
PriorityMultinodeSerializer50())
|
|
serializer.set_critical_nodes(nodes)
|
|
expected_ciritial_roles = [
|
|
{'role': 'mongo', 'fail_if_error': False},
|
|
{'role': 'mongo', 'fail_if_error': False},
|
|
{'role': 'primary-mongo', 'fail_if_error': True},
|
|
{'role': 'controller', 'fail_if_error': True},
|
|
{'role': 'ceph-osd', 'fail_if_error': True},
|
|
{'role': 'other', 'fail_if_error': False}
|
|
]
|
|
self.assertEqual(expected_ciritial_roles, nodes)
|
|
|
|
|
|
class TestNovaOrchestratorHASerializer(OrchestratorSerializerTestBase):
|
|
|
|
def setUp(self):
|
|
super(TestNovaOrchestratorHASerializer, self).setUp()
|
|
self.cluster = self.create_env('ha_compact')
|
|
|
|
def create_env(self, mode):
|
|
cluster = self.env.create(
|
|
cluster_kwargs={
|
|
'mode': mode,
|
|
},
|
|
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.NodeCollection.prepare_for_deployment(cluster_db.nodes)
|
|
return cluster_db
|
|
|
|
@property
|
|
def serializer(self):
|
|
return DeploymentHASerializer(PriorityHASerializer50())
|
|
|
|
def test_set_deployment_priorities(self):
|
|
nodes = [
|
|
{'role': 'zabbix-server'},
|
|
{'role': 'primary-swift-proxy'},
|
|
{'role': 'swift-proxy'},
|
|
{'role': 'storage'},
|
|
{'role': 'mongo'},
|
|
{'role': 'primary-mongo'},
|
|
{'role': 'primary-controller'},
|
|
{'role': 'controller'},
|
|
{'role': 'controller'},
|
|
{'role': 'ceph-osd'},
|
|
{'role': 'other'}
|
|
]
|
|
self.serializer.set_deployment_priorities(nodes)
|
|
expected_priorities = [
|
|
{'role': 'zabbix-server', 'priority': 100},
|
|
{'role': 'primary-swift-proxy', 'priority': 200},
|
|
{'role': 'swift-proxy', 'priority': 300},
|
|
{'role': 'storage', 'priority': 400},
|
|
{'role': 'mongo', 'priority': 500},
|
|
{'role': 'primary-mongo', 'priority': 600},
|
|
{'role': 'primary-controller', 'priority': 700},
|
|
{'role': 'controller', 'priority': 800},
|
|
{'role': 'controller', 'priority': 900},
|
|
{'role': 'ceph-osd', 'priority': 1000},
|
|
{'role': 'other', 'priority': 1000}
|
|
]
|
|
self.assertEqual(expected_priorities, nodes)
|
|
|
|
def test_set_deployment_priorities_many_cntrls(self):
|
|
nodes = [
|
|
{'role': 'zabbix-server'},
|
|
{'role': 'primary-swift-proxy'},
|
|
{'role': 'swift-proxy'},
|
|
{'role': 'storage'},
|
|
{'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'},
|
|
{'role': 'other'}
|
|
]
|
|
self.serializer.set_deployment_priorities(nodes)
|
|
expected_priorities = [
|
|
{'role': 'zabbix-server', 'priority': 100},
|
|
{'role': 'primary-swift-proxy', 'priority': 200},
|
|
{'role': 'swift-proxy', 'priority': 300},
|
|
{'role': 'storage', 'priority': 400},
|
|
{'role': 'mongo', 'priority': 500},
|
|
{'role': 'primary-mongo', 'priority': 600},
|
|
{'role': 'primary-controller', 'priority': 700},
|
|
{'role': 'controller', 'priority': 800},
|
|
{'role': 'controller', 'priority': 900},
|
|
{'role': 'controller', 'priority': 1000},
|
|
{'role': 'controller', 'priority': 1100},
|
|
{'role': 'controller', 'priority': 1200},
|
|
{'role': 'controller', 'priority': 1300},
|
|
{'role': 'controller', 'priority': 1400},
|
|
{'role': 'controller', 'priority': 1500},
|
|
{'role': 'ceph-osd', 'priority': 1600},
|
|
{'role': 'other', 'priority': 1600}
|
|
]
|
|
self.assertEqual(expected_priorities, nodes)
|
|
|
|
def test_set_critital_node(self):
|
|
nodes = [
|
|
{'role': 'zabbix-server'},
|
|
{'role': 'primary-swift-proxy'},
|
|
{'role': 'swift-proxy'},
|
|
{'role': 'storage'},
|
|
{'role': 'mongo'},
|
|
{'role': 'primary-mongo'},
|
|
{'role': 'primary-controller'},
|
|
{'role': 'controller'},
|
|
{'role': 'controller'},
|
|
{'role': 'ceph-osd'},
|
|
{'role': 'other'}
|
|
]
|
|
self.serializer.set_critical_nodes(nodes)
|
|
expected_ciritial_roles = [
|
|
{'role': 'zabbix-server', 'fail_if_error': False},
|
|
{'role': 'primary-swift-proxy', 'fail_if_error': True},
|
|
{'role': 'swift-proxy', 'fail_if_error': False},
|
|
{'role': 'storage', 'fail_if_error': False},
|
|
{'role': 'mongo', 'fail_if_error': False},
|
|
{'role': 'primary-mongo', 'fail_if_error': True},
|
|
{'role': 'primary-controller', 'fail_if_error': True},
|
|
{'role': 'controller', 'fail_if_error': False},
|
|
{'role': 'controller', 'fail_if_error': False},
|
|
{'role': 'ceph-osd', 'fail_if_error': True},
|
|
{'role': 'other', 'fail_if_error': False}
|
|
]
|
|
self.assertEqual(expected_ciritial_roles, 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)
|
|
|
|
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):
|
|
|
|
@property
|
|
def serializer(self):
|
|
return DeploymentHASerializer51(PriorityHASerializer51())
|
|
|
|
def test_set_deployment_priorities(self):
|
|
nodes = [
|
|
{'role': 'zabbix-server'},
|
|
{'role': 'primary-swift-proxy'},
|
|
{'role': 'swift-proxy'},
|
|
{'role': 'storage'},
|
|
{'role': 'mongo'},
|
|
{'role': 'primary-mongo'},
|
|
{'role': 'primary-controller'},
|
|
{'role': 'controller'},
|
|
{'role': 'controller'},
|
|
{'role': 'ceph-osd'},
|
|
{'role': 'other'}
|
|
]
|
|
self.serializer.set_deployment_priorities(nodes)
|
|
expected_priorities = [
|
|
{'role': 'zabbix-server', 'priority': 100},
|
|
{'role': 'primary-swift-proxy', 'priority': 200},
|
|
{'role': 'swift-proxy', 'priority': 300},
|
|
{'role': 'storage', 'priority': 400},
|
|
{'role': 'mongo', 'priority': 500},
|
|
{'role': 'primary-mongo', 'priority': 600},
|
|
{'role': 'primary-controller', 'priority': 700},
|
|
{'role': 'controller', 'priority': 800},
|
|
{'role': 'controller', 'priority': 800},
|
|
{'role': 'ceph-osd', 'priority': 900},
|
|
{'role': 'other', 'priority': 900}
|
|
]
|
|
self.assertEqual(expected_priorities, nodes)
|
|
|
|
def test_set_deployment_priorities_many_cntrls(self):
|
|
nodes = [
|
|
{'role': 'zabbix-server'},
|
|
{'role': 'primary-swift-proxy'},
|
|
{'role': 'swift-proxy'},
|
|
{'role': 'storage'},
|
|
{'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'},
|
|
{'role': 'other'}
|
|
]
|
|
self.serializer.set_deployment_priorities(nodes)
|
|
expected_priorities = [
|
|
{'role': 'zabbix-server', 'priority': 100},
|
|
{'role': 'primary-swift-proxy', 'priority': 200},
|
|
{'role': 'swift-proxy', 'priority': 300},
|
|
{'role': 'storage', 'priority': 400},
|
|
{'role': 'mongo', 'priority': 500},
|
|
{'role': 'primary-mongo', 'priority': 600},
|
|
{'role': 'primary-controller', 'priority': 700},
|
|
{'role': 'controller', 'priority': 800},
|
|
{'role': 'controller', 'priority': 800},
|
|
{'role': 'controller', 'priority': 800},
|
|
{'role': 'controller', 'priority': 800},
|
|
{'role': 'controller', 'priority': 800},
|
|
{'role': 'controller', 'priority': 800},
|
|
{'role': 'controller', 'priority': 900},
|
|
{'role': 'controller', 'priority': 900},
|
|
{'role': 'ceph-osd', 'priority': 1000},
|
|
{'role': 'other', 'priority': 1000}
|
|
]
|
|
self.assertEqual(expected_priorities, nodes)
|
|
|
|
|
|
class TestHASerializerPatching(TestNovaOrchestratorHASerializer):
|
|
|
|
@property
|
|
def serializer(self):
|
|
return DeploymentHASerializer(PriorityHASerializerPatching())
|
|
|
|
def test_set_deployment_priorities(self):
|
|
nodes = [
|
|
{'role': 'zabbix-server'},
|
|
{'role': 'primary-swift-proxy'},
|
|
{'role': 'swift-proxy'},
|
|
{'role': 'storage'},
|
|
{'role': 'mongo'},
|
|
{'role': 'primary-mongo'},
|
|
{'role': 'primary-controller'},
|
|
{'role': 'controller'},
|
|
{'role': 'controller'},
|
|
{'role': 'ceph-osd'},
|
|
{'role': 'other'},
|
|
{'role': 'other'},
|
|
{'role': 'other'},
|
|
]
|
|
self.serializer.set_deployment_priorities(nodes)
|
|
expected_priorities = [
|
|
{'role': 'zabbix-server', 'priority': 100},
|
|
{'role': 'primary-swift-proxy', 'priority': 200},
|
|
{'role': 'swift-proxy', 'priority': 300},
|
|
{'role': 'storage', 'priority': 400},
|
|
{'role': 'mongo', 'priority': 500},
|
|
{'role': 'primary-mongo', 'priority': 600},
|
|
{'role': 'primary-controller', 'priority': 700},
|
|
{'role': 'controller', 'priority': 800},
|
|
{'role': 'controller', 'priority': 900},
|
|
{'role': 'ceph-osd', 'priority': 1000},
|
|
{'role': 'other', 'priority': 1100},
|
|
{'role': 'other', 'priority': 1200},
|
|
{'role': 'other', 'priority': 1300},
|
|
]
|
|
self.assertEqual(expected_priorities, nodes)
|
|
|
|
def test_set_deployment_priorities_many_cntrls(self):
|
|
nodes = [
|
|
{'role': 'zabbix-server'},
|
|
{'role': 'primary-swift-proxy'},
|
|
{'role': 'swift-proxy'},
|
|
{'role': 'storage'},
|
|
{'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'},
|
|
{'role': 'other'}
|
|
]
|
|
self.serializer.set_deployment_priorities(nodes)
|
|
expected_priorities = [
|
|
{'role': 'zabbix-server', 'priority': 100},
|
|
{'role': 'primary-swift-proxy', 'priority': 200},
|
|
{'role': 'swift-proxy', 'priority': 300},
|
|
{'role': 'storage', 'priority': 400},
|
|
{'role': 'mongo', 'priority': 500},
|
|
{'role': 'primary-mongo', 'priority': 600},
|
|
{'role': 'primary-controller', 'priority': 700},
|
|
{'role': 'controller', 'priority': 800},
|
|
{'role': 'controller', 'priority': 900},
|
|
{'role': 'controller', 'priority': 1000},
|
|
{'role': 'controller', 'priority': 1100},
|
|
{'role': 'controller', 'priority': 1200},
|
|
{'role': 'controller', 'priority': 1300},
|
|
{'role': 'controller', 'priority': 1400},
|
|
{'role': 'controller', 'priority': 1500},
|
|
{'role': 'ceph-osd', 'priority': 1600},
|
|
{'role': 'other', 'priority': 1700}
|
|
]
|
|
self.assertEqual(expected_priorities, nodes)
|
|
|
|
|
|
# TODO(awoodward): multinode deprecation: probably has duplicates
|
|
class TestNeutronOrchestratorSerializer(OrchestratorSerializerTestBase):
|
|
|
|
def setUp(self):
|
|
super(TestNeutronOrchestratorSerializer, self).setUp()
|
|
self.new_env_release_version = None
|
|
self.cluster = self.create_env('ha_compact')
|
|
|
|
def create_env(self, mode, segment_type='vlan'):
|
|
release_kwargs = {}
|
|
if self.new_env_release_version:
|
|
release_kwargs['version'] = self.new_env_release_version
|
|
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.NodeCollection.prepare_for_deployment(cluster_db.nodes)
|
|
return cluster_db
|
|
|
|
def serialize_env_w_version(self, version):
|
|
self.new_env_release_version = version
|
|
cluster = self.create_env(mode='ha_compact')
|
|
return create_serializer(cluster).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 = 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 check_5x_60_neutron_attrs(self, version):
|
|
serialized_nodes = self.serialize_env_w_version(version)
|
|
for node in serialized_nodes:
|
|
self.assertEqual(
|
|
{
|
|
"network_type": "local",
|
|
"segment_id": None,
|
|
"router_ext": True,
|
|
"physnet": None
|
|
},
|
|
node['quantum_settings']['predefined_networks'][
|
|
'net04_ext']['L2']
|
|
)
|
|
self.assertFalse(
|
|
'physnet1' in node['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):
|
|
serialized_nodes = self.serialize_env_w_version(version)
|
|
for node in serialized_nodes:
|
|
self.assertEqual(
|
|
{
|
|
"network_type": "flat",
|
|
"segment_id": None,
|
|
"router_ext": True,
|
|
"physnet": "physnet1"
|
|
},
|
|
node['quantum_settings']['predefined_networks'][
|
|
'net04_ext']['L2']
|
|
)
|
|
self.assertEqual(
|
|
{
|
|
"bridge": "br-ex",
|
|
"vlan_range": None
|
|
},
|
|
node['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.NodeCollection.prepare_for_deployment(self.cluster.nodes)
|
|
|
|
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'],
|
|
'node-%d.%s' % (node_db.id, 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.NodeCollection.prepare_for_deployment(self.cluster.nodes)
|
|
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'], 'node-%d' % node_db.id)
|
|
self.assertEqual(
|
|
node['fqdn'],
|
|
'node-%d.%s' % (node_db.id, 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([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': 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.NodeCollection.prepare_for_deployment(self.cluster.nodes)
|
|
serialized_nodes = self.serializer.serialize(self.cluster,
|
|
self.cluster.nodes)
|
|
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.Node.get_network_manager(node_db)
|
|
self.assertEqual(
|
|
net_man._get_ip_by_network_name(
|
|
node_db, 'public') is not None,
|
|
is_public
|
|
)
|
|
|
|
for node_attrs in node['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)
|
|
|
|
self.assertEqual(
|
|
{
|
|
'action': 'add-br',
|
|
'name': 'br-ex'
|
|
} in node['network_scheme']['transformations'],
|
|
is_public
|
|
)
|
|
self.assertEqual(
|
|
{
|
|
'action': 'add-patch',
|
|
'bridges': ['br-eth0', '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('ha_compact', 'gre')
|
|
test_gateway = "192.168.111.255"
|
|
public_ng = self.db.query(NetworkGroup).filter(
|
|
NetworkGroup.name == 'public'
|
|
).filter(
|
|
NetworkGroup.group_id == cluster.default_group
|
|
).first()
|
|
public_ng.gateway = test_gateway
|
|
self.db.add(public_ng)
|
|
self.db.commit()
|
|
|
|
facts = self.serializer.serialize(cluster, cluster.nodes)
|
|
|
|
pd_nets = facts[0]["quantum_settings"]["predefined_networks"]
|
|
self.assertEqual(
|
|
pd_nets["net04_ext"]["L3"]["gateway"],
|
|
test_gateway
|
|
)
|
|
|
|
def test_gre_segmentation(self):
|
|
cluster = self.create_env('ha_compact', 'gre')
|
|
facts = self.serializer.serialize(cluster, cluster.nodes)
|
|
|
|
for fact in facts:
|
|
self.assertEqual(
|
|
fact['quantum_settings']['L2']['segmentation_type'], 'gre')
|
|
self.assertEqual(
|
|
'br-prv' in fact['network_scheme']['endpoints'], False)
|
|
self.assertEqual(
|
|
'private' in (fact['network_scheme']['roles']), False)
|
|
|
|
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(
|
|
cluster_kwargs={
|
|
'net_provider': 'neutron',
|
|
'net_segment_type': segment_type
|
|
},
|
|
nodes_kwargs=[
|
|
{'roles': ['controller'], 'pending_addition': True,
|
|
'meta': meta}
|
|
]
|
|
)
|
|
|
|
cluster_db = self.db.query(Cluster).get(cluster['id'])
|
|
objects.NodeCollection.prepare_for_deployment(cluster_db.nodes)
|
|
return cluster_db
|
|
|
|
def test_vlan_splinters_disabled(self):
|
|
cluster = self._create_cluster_for_vlan_splinters()
|
|
cluster_id = cluster.id
|
|
editable_attrs = self._make_data_copy(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)[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 = self._make_data_copy(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 = cluster.attributes.editable
|
|
self.assertEqual(editable_attrs['vlan_splinters']['vswitch']['value'],
|
|
'some_text')
|
|
|
|
node = self.serializer.serialize(cluster, cluster.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)[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 = self._make_data_copy(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)[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 = self._make_data_copy(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)[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'])
|
|
map(
|
|
lambda n: vlan_set.remove(n) if n else None,
|
|
L2_attrs['trunks']
|
|
)
|
|
self.assertEqual(len(vlan_set), 0)
|
|
|
|
def test_hard_vlan_splinters_in_vlan(self):
|
|
cluster = self._create_cluster_for_vlan_splinters('vlan')
|
|
editable_attrs = self._make_data_copy(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(xrange(*private_vlan_range))
|
|
vlan_set.add(private_vlan_range[1])
|
|
|
|
node = self.serializer.serialize(cluster, cluster.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'])
|
|
map(
|
|
lambda n: vlan_set.remove(n) if n else None,
|
|
L2_attrs['trunks']
|
|
)
|
|
self.assertEqual(len(vlan_set), 0)
|
|
|
|
def test_soft_vlan_splinters_in_vlan(self):
|
|
cluster = self._create_cluster_for_vlan_splinters('vlan')
|
|
editable_attrs = self._make_data_copy(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)[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):
|
|
|
|
def setUp(self):
|
|
super(TestNeutronOrchestratorHASerializer, self).setUp()
|
|
self.cluster = self.create_env('ha_compact')
|
|
|
|
def create_env(self, mode):
|
|
cluster = self.env.create(
|
|
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.NodeCollection.prepare_for_deployment(cluster_db.nodes)
|
|
return cluster_db
|
|
|
|
@property
|
|
def serializer(self):
|
|
return DeploymentHASerializer(PriorityHASerializer50())
|
|
|
|
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):
|
|
|
|
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)
|
|
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):
|
|
self.assertEqual(
|
|
msg,
|
|
{
|
|
'action': 'add-bond',
|
|
'bridge': 'br-ovsbond0',
|
|
'interfaces': ['eth1', 'eth2'],
|
|
'name': 'ovsbond0',
|
|
'properties': ['lacp=active', 'bond_mode=balance-tcp']
|
|
})
|
|
|
|
def check_add_bond_msg_non_lacp(self, msg, mode):
|
|
self.assertEqual(
|
|
msg,
|
|
{
|
|
'action': 'add-bond',
|
|
'bridge': 'br-ovsbond0',
|
|
'interfaces': ['eth1', 'eth2'],
|
|
'name': 'ovsbond0',
|
|
'properties': ['bond_mode={0}'.format(mode)]
|
|
})
|
|
|
|
def check_bond_with_mode(self, mode):
|
|
cluster = self.create_env()
|
|
for node in cluster.nodes:
|
|
self.env.make_bond_via_api('ovsbond0',
|
|
mode,
|
|
['eth1', 'eth2'],
|
|
node.id)
|
|
facts = self.serialize(cluster)
|
|
for node in facts:
|
|
transforms = node['network_scheme']['transformations']
|
|
bonds = filter(lambda t: t['action'] == 'add-bond',
|
|
transforms)
|
|
self.assertEqual(len(bonds), 1)
|
|
if mode == OVS_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):
|
|
for mode in OVS_BOND_MODES:
|
|
self.check_bond_with_mode(mode)
|
|
|
|
|
|
class TestCephOsdImageOrchestratorSerialize(OrchestratorSerializerTestBase):
|
|
|
|
def setUp(self):
|
|
super(TestCephOsdImageOrchestratorSerialize, self).setUp()
|
|
cluster = self.env.create(
|
|
cluster_kwargs={
|
|
'mode': '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'])
|
|
|
|
def test_glance_image_cache_max_size(self):
|
|
data = self.serialize(self.cluster)
|
|
self.assertEqual(len(data), 2)
|
|
# one node - 2 roles
|
|
self.assertEqual(data[0]['uid'], data[1]['uid'])
|
|
self.assertEqual(data[0]['glance']['image_cache_max_size'], '0')
|
|
self.assertEqual(data[1]['glance']['image_cache_max_size'], '0')
|
|
|
|
|
|
class TestCephPgNumOrchestratorSerialize(OrchestratorSerializerTestBase):
|
|
|
|
def create_env(self, nodes, osd_pool_size='2'):
|
|
cluster = self.env.create(
|
|
cluster_kwargs={
|
|
'mode': 'multinode'},
|
|
nodes_kwargs=nodes)
|
|
self.app.patch(
|
|
reverse(
|
|
'ClusterAttributesHandler',
|
|
kwargs={'cluster_id': cluster['id']}),
|
|
params=jsonutils.dumps(
|
|
{'editable': {
|
|
'storage': {
|
|
'osd_pool_size': {'value': osd_pool_size}}}}),
|
|
headers=self.default_headers)
|
|
return self.db.query(Cluster).get(cluster['id'])
|
|
|
|
def test_pg_num_no_osd_nodes(self):
|
|
cluster = self.create_env([
|
|
{'roles': ['controller']}])
|
|
data = self.serialize(cluster)
|
|
self.assertEqual(data[0]['storage']['pg_num'], 128)
|
|
|
|
def test_pg_num_1_osd_node(self):
|
|
cluster = self.create_env([
|
|
{'roles': ['controller', 'ceph-osd']}])
|
|
data = self.serialize(cluster)
|
|
self.assertEqual(data[0]['storage']['pg_num'], 256)
|
|
|
|
def test_pg_num_1_osd_node_repl_4(self):
|
|
cluster = self.create_env(
|
|
[{'roles': ['controller', 'ceph-osd']}],
|
|
'4')
|
|
data = self.serialize(cluster)
|
|
self.assertEqual(data[0]['storage']['pg_num'], 128)
|
|
|
|
def test_pg_num_3_osd_nodes(self):
|
|
cluster = self.create_env([
|
|
{'roles': ['controller', 'ceph-osd']},
|
|
{'roles': ['compute', 'ceph-osd']},
|
|
{'roles': ['compute', 'ceph-osd']}])
|
|
data = self.serialize(cluster)
|
|
self.assertEqual(data[0]['storage']['pg_num'], 512)
|
|
|
|
|
|
class TestMongoNodesSerialization(OrchestratorSerializerTestBase):
|
|
|
|
def create_env(self):
|
|
cluster = self.env.create(
|
|
cluster_kwargs={
|
|
'mode': '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.NodeCollection.prepare_for_deployment(cluster.nodes)
|
|
return cluster
|
|
|
|
@property
|
|
def serializer_ha(self):
|
|
return DeploymentHASerializer(PriorityHASerializer50())
|
|
|
|
@property
|
|
def serializer_mn(self):
|
|
return DeploymentMultinodeSerializer(PriorityMultinodeSerializer50())
|
|
|
|
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)
|
|
|
|
def test_primary_node_selected(self):
|
|
cluster = self.create_env()
|
|
ha_nodes = self.serializer_ha.serialize_nodes(cluster.nodes)
|
|
mn_nodes = self.serializer_mn.serialize_nodes(cluster.nodes)
|
|
|
|
def primary_nodes_count(nodes):
|
|
return len(filter(lambda x: x['role'] == 'primary-mongo', nodes))
|
|
|
|
self.assertEqual(1, primary_nodes_count(ha_nodes))
|
|
self.assertEqual(1, primary_nodes_count(mn_nodes))
|
|
|
|
|
|
class TestRepoAndPuppetDataSerialization(OrchestratorSerializerTestBase):
|
|
|
|
orch_data = {
|
|
"repo_metadata": {
|
|
"nailgun":
|
|
"http://10.20.0.2:8080/centos-5.0/centos/x86_64/"
|
|
},
|
|
"puppet_modules_source":
|
|
"rsync://10.20.0.2/puppet/release/5.0/modules",
|
|
"puppet_manifests_source":
|
|
"rsync://10.20.0.2/puppet/release/5.0/manifests"
|
|
}
|
|
|
|
def test_repo_and_puppet_data_w_orch_data(self):
|
|
release_id = self.env.create_release().id
|
|
|
|
resp = self.app.put(
|
|
reverse('ReleaseHandler', kwargs={'obj_id': release_id}),
|
|
params=jsonutils.dumps(
|
|
{
|
|
"orchestrator_data": self.orch_data
|
|
}
|
|
),
|
|
headers=self.default_headers,
|
|
expect_errors=True
|
|
)
|
|
self.assertEqual(200, resp.status_code)
|
|
|
|
cluster_id = self.env.create(
|
|
cluster_kwargs={
|
|
'release_id': release_id
|
|
},
|
|
nodes_kwargs=[
|
|
{'roles': ['controller'], 'pending_addition': True}
|
|
]
|
|
)["id"]
|
|
|
|
cluster = self.db.query(Cluster).get(cluster_id)
|
|
objects.NodeCollection.prepare_for_deployment(cluster.nodes)
|
|
facts = self.serializer.serialize(cluster, cluster.nodes)
|
|
|
|
self.assertEqual(1, len(facts))
|
|
fact = facts[0]
|
|
self.assertEqual(
|
|
fact['repo_metadata'],
|
|
{
|
|
'nailgun': 'http://10.20.0.2:8080'
|
|
'/centos-5.0/centos/x86_64/'
|
|
}
|
|
)
|
|
self.assertEqual(
|
|
fact['puppet_modules_source'],
|
|
'rsync://10.20.0.2/puppet/release/5.0/modules'
|
|
)
|
|
self.assertEqual(
|
|
fact['puppet_manifests_source'],
|
|
'rsync://10.20.0.2/puppet/release/5.0/manifests'
|
|
)
|
|
|
|
def test_repo_and_puppet_data_wo_orch_data(self):
|
|
release_id = self.env.create_release().id
|
|
|
|
cluster_id = self.env.create(
|
|
cluster_kwargs={
|
|
'release_id': release_id
|
|
},
|
|
nodes_kwargs=[
|
|
{'roles': ['controller'], 'pending_addition': True}
|
|
]
|
|
)["id"]
|
|
|
|
cluster = self.db.query(Cluster).get(cluster_id)
|
|
objects.NodeCollection.prepare_for_deployment(cluster.nodes)
|
|
facts = self.serializer.serialize(cluster, cluster.nodes)
|
|
|
|
self.assertEqual(1, len(facts))
|
|
fact = facts[0]
|
|
self.assertEqual(
|
|
fact['repo_metadata'],
|
|
{
|
|
'nailgun': 'http://127.0.0.1:8080/centos/x86_64'
|
|
}
|
|
)
|
|
self.assertEqual(
|
|
fact['puppet_modules_source'],
|
|
'rsync://127.0.0.1:/puppet/modules/'
|
|
)
|
|
self.assertEqual(
|
|
fact['puppet_manifests_source'],
|
|
'rsync://127.0.0.1:/puppet/manifests/'
|
|
)
|
|
|
|
def test_orch_data_w_replaced_deployment_info(self):
|
|
replaced_deployment_info = [{'repo_metadata': 'custom_stuff'}]
|
|
release = self.env.create_release()
|
|
self.env.create(
|
|
cluster_kwargs={'release_id': release.id},
|
|
nodes_kwargs=[
|
|
{'roles': ['controller'], 'pending_addition': True}
|
|
])
|
|
objects.Release.update_orchestrator_data(release, self.orch_data)
|
|
self.db.flush()
|
|
self.db.refresh(release)
|
|
self.env.nodes[0].replaced_deployment_info = replaced_deployment_info
|
|
|
|
facts = self.serializer.serialize(
|
|
self.env.clusters[0], self.env.nodes)
|
|
self.assertEqual(facts[0]['repo_metadata'],
|
|
self.orch_data['repo_metadata'])
|
|
self.assertEqual(facts[0]['puppet_modules_source'],
|
|
self.orch_data['puppet_modules_source'])
|
|
self.assertEqual(facts[0]['puppet_manifests_source'],
|
|
self.orch_data['puppet_manifests_source'])
|
|
|
|
|
|
class TestNSXOrchestratorSerializer(OrchestratorSerializerTestBase):
|
|
|
|
def setUp(self):
|
|
super(TestNSXOrchestratorSerializer, self).setUp()
|
|
self.cluster = self.create_env('ha_compact')
|
|
|
|
def create_env(self, mode, segment_type='gre'):
|
|
cluster = self.env.create(
|
|
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 = self._make_data_copy(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.NodeCollection.prepare_for_deployment(cluster_db.nodes)
|
|
return cluster_db
|
|
|
|
def test_serialize_node(self):
|
|
serialized_data = self.serializer.serialize(self.cluster,
|
|
self.cluster.nodes)[0]
|
|
|
|
q_settings = serialized_data['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)
|