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

1271 lines
49 KiB
Python

# -*- coding: utf-8 -*-
# Copyright 2015 Mirantis, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
import six
from oslo_serialization import jsonutils
import unittest2
from nailgun import consts
from nailgun.db.sqlalchemy import models
from nailgun import objects
from nailgun.orchestrator import deployment_serializers
from nailgun import plugins
from nailgun.utils import reverse
from nailgun.extensions.network_manager.serializers.neutron_serializers \
import NeutronNetworkDeploymentSerializer90
from nailgun.extensions.network_manager.serializers.neutron_serializers \
import NeutronNetworkTemplateSerializer90
from nailgun.test.integration import test_orchestrator_serializer_80
class TestSerializer90Mixin(object):
env_version = "mitaka-9.0"
task_deploy = True
dpdk_bridge_provider = consts.NEUTRON_L23_PROVIDERS.ovs
@classmethod
def create_serializer(cls, cluster):
serializer_type = deployment_serializers.get_serializer_for_cluster(
cluster
)
return serializer_type(None)
@staticmethod
def _get_serializer(cluster):
return deployment_serializers.DeploymentLCMSerializer()
@staticmethod
def _get_nodes_count_in_astute_info(nodes):
"""Count number of node in deployment info for LCM serializer
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.
Number of elements in deployment info for LCM serializer is equal
with node's number in a cluster.
:param nodes: array of cluster nodes
:returns: expected number of elements in deployment info
"""
return len(nodes)
@staticmethod
def _handle_facts(facts):
"""Handle deployment facts for LCM serializers
As we are running 7.0 tests against 9.0 environments where
LCM serializer is used it's not expected to have master node
in the list of serialized nodes.
:param facts: deployment info produced by LCM serializer
:returns: deployment info without master node data
"""
return [node for node in facts
if node.get('roles') != [consts.TASK_ROLES.master]]
class TestDeploymentAttributesSerialization90(
TestSerializer90Mixin,
test_orchestrator_serializer_80.TestDeploymentAttributesSerialization80
):
def serialize(self):
objects.Cluster.prepare_for_deployment(self.cluster_db)
return self.serializer.serialize(
self.cluster_db, self.cluster_db.nodes)
def _assign_dpdk_to_nic(self, node, dpdk_nic, other_nic):
node.attributes['cpu_pinning']['dpdk']['value'] = 2
other_nets = other_nic.assigned_networks_list
dpdk_nets = dpdk_nic.assigned_networks_list
for i, net in enumerate(other_nets):
if net['name'] == 'private':
dpdk_nets.append(other_nets.pop(i))
break
objects.NIC.assign_networks(other_nic, other_nets)
objects.NIC.assign_networks(dpdk_nic, dpdk_nets)
objects.NIC.update(dpdk_nic, {
'meta': {
'dpdk': {'available': True},
'pci_id': 'test_id:2'
},
'attributes': {'dpdk': {'enabled': {'value': True}}}
})
def _create_cluster_with_vxlan(self):
release_id = self.cluster_db.release.id
self.cluster = self.env.create(
cluster_kwargs={
'mode': consts.CLUSTER_MODES.ha_compact,
'net_provider': consts.CLUSTER_NET_PROVIDERS.neutron,
'net_segment_type': consts.NEUTRON_SEGMENT_TYPES.tun,
'release_id': release_id})
self.cluster_db = self.db.query(models.Cluster).get(self.cluster['id'])
self.serializer = self.create_serializer(self.cluster_db)
def _get_br_name_by_segmentation_type(self):
if (self.cluster.network_config.segmentation_type ==
consts.NEUTRON_SEGMENT_TYPES.vlan):
return consts.DEFAULT_BRIDGES_NAMES.br_prv
return consts.DEFAULT_BRIDGES_NAMES.br_mesh
@mock.patch('nailgun.objects.Release.get_supported_dpdk_drivers')
def _check_dpdk_serializing(self, drivers_mock, has_vlan_tag=False,
sriov=False, max_queues=0,
dpdk_cpu_pinning=0):
drivers_mock.return_value = {
'driver_1': ['test_id:1', 'test_id:2']
}
node = self.env.create_nodes_w_interfaces_count(
1, 3,
cluster_id=self.cluster_db.id,
roles=['compute'])[0]
node.interfaces[0].attributes['sriov']['enabled']['value'] = sriov
if has_vlan_tag:
objects.NetworkGroup.get_node_network_by_name(
node, 'private').vlan_start = '103'
other_nic = node.interfaces[0]
dpdk_nic = node.interfaces[2]
self._assign_dpdk_to_nic(node, dpdk_nic, other_nic)
dpdk_interface_name = dpdk_nic.name
dpdk_nic.meta['max_queues'] = max_queues
if dpdk_cpu_pinning:
node.attributes['cpu_pinning']['dpdk']['value'] = dpdk_cpu_pinning
objects.Cluster.prepare_for_deployment(self.cluster_db)
br_name = self._get_br_name_by_segmentation_type()
serialized_for_astute = self.serializer.serialize(
self.cluster_db, self.cluster_db.nodes)
self.assertEqual(len(self._handle_facts(
serialized_for_astute['nodes'])), 1)
serialized_node = serialized_for_astute['nodes'][0]
dpdk = serialized_node.get('dpdk')
vendor_specific = {'datapath_type': 'netdev'}
vlan_id = objects.NetworkGroup.get_node_network_by_name(
node, 'private').vlan_start
if br_name == consts.DEFAULT_BRIDGES_NAMES.br_mesh and vlan_id:
vendor_specific['vlan_id'] = vlan_id
self.assertIsNotNone(dpdk)
self.assertTrue(dpdk.get('enabled'))
transformations = serialized_node['network_scheme']['transformations']
private_br = filter(lambda t: t.get('name') == br_name,
transformations)[0]
dpdk_ports = filter(lambda t: t.get('name') == dpdk_interface_name,
transformations)
all_ports = filter(lambda t: t.get('action') == 'add-port',
transformations)
self.assertEqual(private_br.get('vendor_specific'),
vendor_specific)
self.assertEqual(private_br.get('provider'), self.dpdk_bridge_provider)
self.assertEqual(len(all_ports) - len(dpdk_ports),
len(other_nic.assigned_networks_list))
self.assertEqual(len(dpdk_ports), 1)
self.assertEqual(dpdk_ports[0]['bridge'], br_name)
self.assertEqual(dpdk_ports[0].get('provider'),
consts.NEUTRON_L23_PROVIDERS.dpdkovs)
interfaces = serialized_node['network_scheme']['interfaces']
dpdk_interface = interfaces[dpdk_interface_name]
vendor_specific = dpdk_interface.get('vendor_specific', {})
if sriov:
self.assertEqual(vendor_specific.get('dpdk_driver'), 'vfio-pci')
else:
self.assertEqual(vendor_specific.get('dpdk_driver'), 'driver_1')
if max_queues > 1 and dpdk_cpu_pinning > 2:
self.assertEqual(vendor_specific.get('max_queues'),
min(max_queues, dpdk_cpu_pinning - 1))
else:
self.assertFalse('max_queues' in vendor_specific)
def test_serialization_with_dpdk(self):
self._check_dpdk_serializing()
def test_serialization_with_dpdk_sriov(self):
self._check_dpdk_serializing(sriov=True)
def test_serialization_with_dpdk_vxlan(self):
self._create_cluster_with_vxlan()
self._check_dpdk_serializing()
def test_serialization_with_dpdk_vxlan_with_vlan_tag(self):
self._create_cluster_with_vxlan()
self._check_dpdk_serializing(has_vlan_tag=True)
def test_serialization_with_dpdk_queues_limited_max_queues(self):
max_queues = 2
dpdk_cpu_pinning = 4
self._check_dpdk_serializing(max_queues=max_queues,
dpdk_cpu_pinning=dpdk_cpu_pinning)
def test_serialization_with_dpdk_queues_limited_dpdk_cpu_pinning(self):
max_queues = 4
dpdk_cpu_pinning = 3
self._check_dpdk_serializing(max_queues=max_queues,
dpdk_cpu_pinning=dpdk_cpu_pinning)
@mock.patch('nailgun.objects.Release.get_supported_dpdk_drivers')
def _check_dpdk_bond_serializing(self, attributes, drivers_mock):
drivers_mock.return_value = {
'driver_1': ['test_id:1', 'test_id:2']
}
node = self.env.create_nodes_w_interfaces_count(
1, 4,
cluster_id=self.cluster_db.id,
roles=['compute'])[0]
node.attributes['hugepages'] = {
'dpdk': {'type': 'number', 'value': 1024},
'nova': {'type': 'custom_hugepages', 'value': {'2048': 1}}
}
node.attributes['cpu_pinning']['dpdk']['value'] = 3
cluster_attrs = objects.Cluster.get_editable_attributes(node.cluster)
cluster_attrs['common']['libvirt_type'].update(
{'value': consts.HYPERVISORS.kvm})
objects.Cluster.update_attributes(
node.cluster, {'editable': cluster_attrs})
for iface in node.interfaces:
iface['meta'].update({'pci_id': 'test_id:1'})
iface['meta']['dpdk']['available'] = True
interfaces = self.env.node_nics_get(node.id).json_body
first_nic = interfaces[0]
nics_for_bond = [interfaces.pop(), interfaces.pop()]
networks_for_bond = []
bond_interface_name = 'bond0'
first_nic_networks = first_nic['assigned_networks']
for i, net in enumerate(first_nic_networks):
if net['name'] == 'private':
networks_for_bond.append(first_nic_networks.pop(i))
break
attributes.update(
{'dpdk': {'enabled': {'value': True}}})
bond_interface = {
'name': bond_interface_name,
'type': consts.NETWORK_INTERFACE_TYPES.bond,
'slaves': nics_for_bond,
'assigned_networks': networks_for_bond,
'attributes': attributes}
interfaces.append(bond_interface)
self.env.node_nics_put(node.id, interfaces)
serialized_for_astute = self.serialize()
self.assertEqual(len(self._handle_facts(
serialized_for_astute['nodes'])), 1)
serialized_node = serialized_for_astute['nodes'][0]
dpdk = serialized_node.get('dpdk')
br_name = self._get_br_name_by_segmentation_type()
vendor_specific = {'datapath_type': 'netdev'}
if br_name == consts.DEFAULT_BRIDGES_NAMES.br_mesh:
vendor_specific['vlan_id'] = \
objects.NetworkGroup.get_node_network_by_name(
node, 'private').vlan_start
self.assertIsNotNone(dpdk)
self.assertTrue(dpdk.get('enabled'))
transformations = serialized_node['network_scheme']['transformations']
private_br = filter(lambda t: t.get('name') == br_name,
transformations)[0]
dpdk_bonds = filter(lambda t: t.get('name') ==
bond_interface_name,
transformations)
self.assertEqual(len(dpdk_bonds), 1)
self.assertEqual(dpdk_bonds[0]['bridge'], br_name)
self.assertEqual(
private_br.get('vendor_specific'), vendor_specific)
self.assertEqual(
dpdk_bonds[0].get('provider'),
consts.NEUTRON_L23_PROVIDERS.dpdkovs)
self.assertEqual(
dpdk_bonds[0].get('bond_properties').get('mode'),
attributes.get('mode', {}).get('value', {}).get('value'))
interfaces = serialized_node['network_scheme']['interfaces']
for iface in nics_for_bond:
dpdk_interface = interfaces[iface['name']]
vendor_specific = dpdk_interface.get('vendor_specific', {})
self.assertEqual(vendor_specific.get('dpdk_driver'), 'driver_1')
def test_serialization_with_dpdk_on_bond(self):
attributes = {
'mode': {'value': {'value': consts.BOND_MODES.balance_slb}},
'type__': {'value': consts.BOND_TYPES.dpdkovs}
}
self._check_dpdk_bond_serializing(attributes)
def test_serialization_with_dpdk_on_lacp_bond(self):
attributes = {
'mode': {'value': {'value': consts.BOND_MODES.balance_tcp}},
'lacp': {'value': {'value': 'active'}},
'lacp_rate': {'value': {'value': 'fast'}},
'xmit_hash_policy': {'value': {'value': 'layer2'}},
'type__': {'value': consts.BOND_TYPES.dpdkovs}
}
self._check_dpdk_bond_serializing(attributes)
def test_serialization_with_vxlan_dpdk_on_bond(self):
self._create_cluster_with_vxlan()
attributes = {
'mode': {'value': {'value': consts.BOND_MODES.balance_slb}},
'type__': {'value': consts.BOND_TYPES.dpdkovs},
}
self._check_dpdk_bond_serializing(attributes)
def test_serialization_with_vxlan_dpdk_on_lacp_bond(self):
self._create_cluster_with_vxlan()
attributes = {
'mode': {'value': {'value': consts.BOND_MODES.balance_tcp}},
'lacp': {'value': {'value': 'active'}},
'lacp_rate': {'value': {'value': 'fast'}},
'xmit_hash_policy': {'value': {'value': 'layer2'}},
'type__': {'value': consts.BOND_TYPES.dpdkovs}
}
self._check_dpdk_bond_serializing(attributes)
def test_attributes_cpu_pinning(self):
numa_nodes = [
{'id': 0, 'memory': 2 ** 31, 'cpus': [1, 2, 3, 4]},
{'id': 1, 'memory': 2 ** 31, 'cpus': [5, 6, 7, 8]}
]
node = self.env.create_nodes_w_interfaces_count(
1, 3,
cluster_id=self.cluster_db.id,
roles=['compute'])[0]
other_nic = node.interfaces[0]
dpdk_nic = node.interfaces[2]
self._assign_dpdk_to_nic(node, dpdk_nic, other_nic)
node.meta['numa_topology']['numa_nodes'] = numa_nodes
node.attributes.update({
'cpu_pinning': {
'nova': {'value': 2},
'dpdk': {'value': 2},
}
})
serialized_for_astute = self.serialize()
serialized_node = serialized_for_astute['nodes'][0]
self.assertEqual(serialized_node['dpdk']['ovs_core_mask'], '0x2')
self.assertEqual(serialized_node['dpdk']['ovs_pmd_core_mask'], '0x4')
self.assertEqual(serialized_node['nova']['cpu_pinning'], [5, 6])
node_name = objects.Node.get_slave_name(node)
network_data = serialized_for_astute['common']['network_metadata']
node_common_attrs = network_data['nodes'][node_name]
self.assertTrue(node_common_attrs['nova_cpu_pinning_enabled'])
def test_pinning_cpu_for_dpdk(self):
numa_nodes = [
{'id': 0, 'memory': 2 ** 31, 'cpus': [1, 2, 3, 4]},
{'id': 1, 'memory': 2 ** 31, 'cpus': [5, 6, 7, 8]}
]
node = self.env.create_nodes_w_interfaces_count(
1, 3,
cluster_id=self.cluster_db.id,
roles=['compute'])[0]
other_nic = node.interfaces[0]
dpdk_nic = node.interfaces[2]
self._assign_dpdk_to_nic(node, dpdk_nic, other_nic)
node.meta['numa_topology']['numa_nodes'] = numa_nodes
node.attributes.update({
'cpu_pinning': {
'dpdk': {'value': 2},
}
})
objects.Cluster.prepare_for_deployment(self.cluster_db)
serialized_for_astute = self.serializer.serialize(
self.cluster_db, self.cluster_db.nodes)
serialized_node = serialized_for_astute['nodes'][0]
self.assertEqual(serialized_node['dpdk']['ovs_core_mask'], '0x2')
self.assertEqual(serialized_node['dpdk']['ovs_pmd_core_mask'], '0x4')
self.assertNotIn('cpu_pinning', serialized_node.get('nova', {}))
node_name = objects.Node.get_slave_name(node)
network_data = serialized_for_astute['common']['network_metadata']
node_common_attrs = network_data['nodes'][node_name]
self.assertFalse(node_common_attrs['nova_cpu_pinning_enabled'])
def test_pinning_cpu_for_nova(self):
numa_nodes = [
{'id': 0, 'memory': 2 ** 31, 'cpus': [1, 2, 3, 4]},
{'id': 1, 'memory': 2 ** 31, 'cpus': [5, 6, 7, 8]}
]
node = self.env.create_node(
cluster_id=self.cluster_db.id,
roles=['compute'])
node.meta['numa_topology']['numa_nodes'] = numa_nodes
node.attributes.update({
'cpu_pinning': {
'nova': {'value': 2},
}
})
objects.Cluster.prepare_for_deployment(self.cluster_db)
serialized_for_astute = self.serializer.serialize(
self.cluster_db, self.cluster_db.nodes)
serialized_node = serialized_for_astute['nodes'][0]
self.assertNotIn('dpdk', serialized_node)
self.assertEqual(serialized_node['nova']['cpu_pinning'], [1, 2])
node_name = objects.Node.get_slave_name(node)
network_data = serialized_for_astute['common']['network_metadata']
node_common_attrs = network_data['nodes'][node_name]
self.assertTrue(node_common_attrs['nova_cpu_pinning_enabled'])
def test_attributes_override_core_mask(self):
numa_nodes = [
{'id': 0, 'memory': 2 ** 31, 'cpus': [1, 2, 3, 4]},
{'id': 1, 'memory': 2 ** 31, 'cpus': [5, 6, 7, 8]}
]
node = self.env.create_nodes_w_interfaces_count(
1, 3,
cluster_id=self.cluster_db.id,
roles=['compute'])[0]
other_nic = node.interfaces[0]
dpdk_nic = node.interfaces[2]
self._assign_dpdk_to_nic(node, dpdk_nic, other_nic)
node.meta['numa_topology']['numa_nodes'] = numa_nodes
node.attributes.update({
'cpu_pinning': {
'nova': {'value': 2},
'dpdk': {'value': 2},
},
'dpdk': {
'ovs_pmd_core_mask': '0x3',
'ovs_core_mask': '0x1'
}
})
serialized_for_astute = self.serialize()
serialized_node = serialized_for_astute['nodes'][0]
self.assertEqual(serialized_node['dpdk']['ovs_core_mask'], '0x1')
self.assertEqual(serialized_node['dpdk']['ovs_pmd_core_mask'], '0x3')
def test_dpdk_hugepages(self):
numa_nodes = []
for i in six.moves.range(3):
numa_nodes.append({
'id': i,
'cpus': [i],
'memory': 2 * 1024 ** 3
})
meta = {
'numa_topology': {
'supported_hugepages': [2048],
'numa_nodes': numa_nodes
}
}
node = self.env.create_node(
cluster_id=self.cluster_db.id,
roles=['compute'],
meta=meta)
node.interfaces[0].attributes.get('dpdk', {}).get(
'enabled', {})['value'] = True
node.attributes.update({
'hugepages': {
'dpdk': {
'value': 1024},
'nova': {
'value': {'2048': 1}}}}
)
serialized_for_astute = self.serialize()
serialized_node = serialized_for_astute['nodes'][0]
self.assertEquals(
[1024, 1024, 1024],
serialized_node['dpdk']['ovs_socket_mem'])
self.assertTrue(serialized_node['nova']['enable_hugepages'])
def test_attributes_no_hugepages_distribution_with_gig_hugepage(self):
meta = {
'numa_topology': {
'supported_hugepages': [2048, 1048576],
'numa_nodes': [
{'id': 0, 'memory': 2 ** 31, 'cpus': [1, 2, 3, 4]},
{'id': 1, 'memory': 2 ** 31, 'cpus': [5, 6, 7, 8]}],
}
}
node = self.env.create_node(
cluster_id=self.cluster_db.id,
roles=['compute'],
meta=meta)
node.attributes.update({
'hugepages': {
'nova': {
'type': 'custom_hugepages',
'value': {
'2048': 512,
'1048576': 1
}
},
'dpdk': {
'type': 'number',
'value': 512,
}
}
})
serialized_for_astute = self.serialize()
serialized_node = serialized_for_astute['nodes'][0]
self.assertNotIn('hugepages', serialized_node)
def test_attributes_hugepages_distribution(self):
meta = {
'numa_topology': {
'supported_hugepages': [2048, 1048576],
'numa_nodes': [
{'id': 0, 'memory': 2 ** 31, 'cpus': [1, 2, 3, 4]},
{'id': 1, 'memory': 2 ** 31, 'cpus': [5, 6, 7, 8]}],
}
}
node = self.env.create_node(
cluster_id=self.cluster_db.id,
roles=['compute'],
meta=meta)
node.attributes.update({
'hugepages': {
'nova': {
'type': 'custom_hugepages',
'value': {
'2048': 512,
}
},
'dpdk': {
'type': 'number',
'value': 512,
}
}
})
serialized_for_astute = self.serialize()
serialized_node = serialized_for_astute['nodes'][0]
expected = [
{'numa_id': 0, 'size': 2048, 'count': 512},
{'numa_id': 1, 'size': 2048, 'count': 512},
]
self.assertEqual(serialized_node['hugepages'], expected)
def test_cpu_pinning_disabled(self):
nodes_roles = [['compute'], ['controller']]
for roles in nodes_roles:
self.env.create_node(
cluster_id=self.cluster_db.id,
roles=roles)
serialized_for_astute = self.serialize()
for serialized_node in serialized_for_astute['nodes']:
nova = serialized_node.get('nova', {})
self.assertNotIn('cpu_pinning', nova)
dpdk = serialized_node.get('dpdk', {})
self.assertNotIn('ovs_core_mask', dpdk)
self.assertNotIn('ovs_pmd_core_mask', dpdk)
network_data = serialized_for_astute['common']['network_metadata']
for node_attrs in six.itervalues(network_data['nodes']):
self.assertFalse(node_attrs['nova_cpu_pinning_enabled'])
def test_hugepages_disabled(self):
nodes_roles = [['compute'], ['controller']]
for roles in nodes_roles:
self.env.create_node(
cluster_id=self.cluster_db.id,
roles=roles)
serialized_for_astute = self.serialize()
for serialized_node in serialized_for_astute['nodes']:
nova = serialized_node.get('nova', {})
self.assertFalse(nova.get('enable_hugepages', False))
dpdk = serialized_node.get('dpdk', {})
self.assertNotIn('ovs_socket_mem', dpdk)
self.assertNotIn('hugepages', serialized_node)
network_data = serialized_for_astute['common']['network_metadata']
for node_attrs in six.itervalues(network_data['nodes']):
self.assertFalse(node_attrs['nova_hugepages_enabled'])
def test_immutable_metadata_key(self):
node = self.env.create_node(
api=True,
cluster_id=self.cluster_db.id,
pending_roles=['controller'],
pending_addition=True)
self.db.flush()
resp = self.app.put(
reverse('NodeHandler', kwargs={'obj_id': node['id']}),
jsonutils.dumps({'hostname': 'new-name'}),
headers=self.default_headers)
self.assertEqual(200, resp.status_code)
serialized_for_astute = self.serialize()
network_data = serialized_for_astute['common']['network_metadata']
for k, v in six.iteritems(network_data['nodes']):
node = objects.Node.get_by_uid(v['uid'])
self.assertEqual(objects.Node.permanent_id(node), k)
def test_plugin_interface_attributes_in_network_schema(self):
interface_offloading = [
{
'name': 'tx-checksumming',
'state': True,
'sub': [
{
'name': 'tx-checksum-ipv6',
'state': None,
'sub': []
}
]
},
{
'name': 'rx-checksumming',
'state': False,
'sub': []
}
]
offloading_modes_states = {
'tx-checksumming': True,
'tx-checksum-ipv6': False,
'rx-checksumming': None
}
node = self.env.create_node(
cluster_id=self.cluster.id,
roles=['controller']
)
self.env.create_plugin(
name='test_plugin',
package_version='5.0.0',
cluster=self.cluster,
nic_attributes_metadata={
'attribute_a': {
'label': 'Interface attribute A',
'value': 'attribute_a_val'
},
'attribute_b': {
'label': 'Interface attribute B',
'value': 'attribute_b_val'
}
}
)
for nic_interface in node.nic_interfaces:
# set default values in meta for offloadin modes
nic_interface.meta['offloading_modes'] = interface_offloading
# change offloading modes via attributes
nic_interface.attributes.update({
'offloading': {'modes': {'value': offloading_modes_states}},
'mtu': {'value': {'value': 2000}},
})
self.db.flush()
serialized_data = self.serialize()['nodes'][0]
serialized_interfaces = serialized_data['network_scheme']['interfaces']
for nic_interface in node.nic_interfaces:
nic_name = nic_interface.name
self.assertEqual(2000, serialized_interfaces[nic_name].get('mtu'))
vendor_specific = serialized_interfaces[nic_name].get(
'vendor_specific', {})
self.assertEqual('attribute_a_val',
vendor_specific.get('attribute_a'))
self.assertEqual('attribute_b_val',
vendor_specific.get('attribute_b'))
self.assertDictEqual(
{
'offload': {'tx-checksumming': True,
'tx-checksum-ipv6': False,
'rx-checksumming': None}
},
serialized_interfaces[nic_name].get('ethtool')
)
def test_plugin_bond_attributes_in_network_schema(self):
node = self.env.create_nodes_w_interfaces_count(
1, 2, **{'cluster_id': self.cluster_db.id,
'roles': ['controller']})[0]
bond_config = {
'type__': {'value': consts.BOND_TYPES.linux},
'mode': {'value': {'value': consts.BOND_MODES.balance_rr}}}
nic_names = [iface.name for iface in node.nic_interfaces]
self.env.make_bond_via_api(
'lnx_bond', '', nic_names, node.id, attrs=bond_config)
self.env.create_plugin(
name='test_plugin',
package_version='5.0.0',
cluster=self.cluster_db,
bond_attributes_metadata={
'attribute_a': {
'label': 'Bond attribute A',
'value': 'attribute_a_val'
},
'attribute_b': {
'label': 'Bond attribute B',
'value': 'attribute_b_val'
}
}
)
serialized_data = self.serialize()['nodes'][0]
for t in serialized_data['network_scheme']['transformations']:
if t.get('name') == 'lnx_bond':
vendor_interface_properties = \
t.get('interface_properties').get('vendor_specific', {})
self.assertEqual(
'attribute_a_val',
vendor_interface_properties.get('attribute_a')
)
self.assertEqual(
'attribute_b_val',
vendor_interface_properties.get('attribute_b')
)
class TestDeploymentLCMSerialization90(
TestSerializer90Mixin,
test_orchestrator_serializer_80.BaseDeploymentSerializer
):
def setUp(self):
super(TestDeploymentLCMSerialization90, self).setUp()
self.cluster = self.env.create(
release_kwargs={
'version': self.env_version,
'operating_system': consts.RELEASE_OS.ubuntu
},
cluster_kwargs={
'mode': consts.CLUSTER_MODES.ha_compact,
'net_provider': consts.CLUSTER_NET_PROVIDERS.neutron,
'net_segment_type': consts.NEUTRON_SEGMENT_TYPES.vlan})
self.cluster_db = self.env.clusters[-1]
self.node = self.env.create_node(
cluster_id=self.cluster_db.id, roles=['compute']
)
self.initialize_serrializer()
def initialize_serrializer(self):
self.serializer = self.create_serializer(self.cluster_db)
@classmethod
def create_serializer(cls, cluster):
return deployment_serializers.DeploymentLCMSerializer()
def test_inject_provision_node_with_node_replaced_provisioning_info(self):
objects.Cluster.prepare_for_deployment(self.cluster_db)
test_provisioning_info = {'test': 123}
self.node.replaced_provisioning_info = test_provisioning_info
data = {}
self.serializer.inject_provision_info(self.node, data)
self.assertIn('provision', data)
self.assertEqual(test_provisioning_info, data['provision'])
def test_openstack_configuration_in_serialized(self):
self.env.create_openstack_config(
cluster_id=self.cluster_db.id,
configuration={
'glance_config': 'value1',
'nova_config': 'value1',
'ceph_config': 'value1'
}
)
self.env.create_openstack_config(
cluster_id=self.cluster_db.id, node_role='compute',
configuration={'ceph_config': 'value2'}
)
self.env.create_openstack_config(
cluster_id=self.cluster_db.id, node_id=self.node.id,
configuration={'nova_config': 'value3'}
)
objects.Cluster.prepare_for_deployment(self.cluster_db)
serialized = self.serializer.serialize(self.cluster_db, [self.node])
self.assertEqual(
{'glance_config': 'value1',
'nova_config': 'value3',
'ceph_config': 'value2'},
serialized['nodes'][0]['configuration']
)
def test_openstack_configuration_options_in_serialized(self):
conf_options = {
'apply_on_deploy': False
}
self.env.create_openstack_config(
cluster_id=self.cluster_db.id,
configuration={
'glance_config': 'value1',
'nova_config': 'value1',
'ceph_config': 'value1',
'configuration_options': conf_options
}
)
objects.Cluster.prepare_for_deployment(self.cluster_db)
serialized = self.serializer.serialize(self.cluster_db, [self.node])
node_info = serialized['nodes'][0]
self.assertIn('configuration', node_info)
self.assertIn('configuration_options', node_info)
self.assertNotIn('configuration_options', node_info['configuration'])
self.assertEqual(conf_options, node_info['configuration_options'])
def test_cluster_attributes_in_serialized(self):
objects.Cluster.prepare_for_deployment(self.cluster_db)
serialized = self.serializer.serialize(self.cluster_db, [self.node])
release = self.cluster_db.release
release_info = {
'name': release.name,
'version': release.version,
'operating_system': release.operating_system,
}
cluster_info = {
"id": self.cluster_db.id,
"name": self.cluster_db.name,
"fuel_version": self.cluster_db.fuel_version,
"status": self.cluster_db.status,
"mode": self.cluster_db.mode
}
self.assertEqual(cluster_info, serialized['common']['cluster'])
self.assertEqual(release_info, serialized['common']['release'])
self.assertEqual(['compute'], serialized['nodes'][0]['roles'])
self.assertEqual(
[consts.TASK_ROLES.master], serialized['nodes'][1]['roles']
)
def test_inactive_cluster_attributes_in_serialized(self):
objects.OpenstackConfig.create({
"cluster_id": self.cluster_db.id,
"node_id": self.node.id,
"node_role": "ceph-osd",
"configuration": {},
})
objects.OpenstackConfig.disable_by_nodes([self.node])
self.initialize_serrializer()
objects.Cluster.prepare_for_deployment(self.cluster_db)
serialized = self.serializer.serialize(self.cluster_db, [self.node])
release = self.cluster_db.release
release_info = {
'name': release.name,
'version': release.version,
'operating_system': release.operating_system,
}
cluster_info = {
"id": self.cluster_db.id,
"name": self.cluster_db.name,
"fuel_version": self.cluster_db.fuel_version,
"status": self.cluster_db.status,
"mode": self.cluster_db.mode
}
self.assertEqual(cluster_info, serialized['common']['cluster'])
self.assertEqual(release_info, serialized['common']['release'])
self.assertEqual(['compute'], serialized['nodes'][0]['roles'])
self.assertEqual(
[consts.TASK_ROLES.master], serialized['nodes'][1]['roles']
)
@mock.patch.object(
plugins.adapters.PluginAdapterBase, 'repo_files',
mock.MagicMock(return_value=True)
)
def test_plugins_in_serialized(self):
releases = [
{'repository_path': 'repositories/ubuntu',
'version': self.env_version, 'os': 'ubuntu',
'mode': ['ha', 'multinode'],
'deployment_scripts_path': 'deployment_scripts/'}
]
plugin1 = self.env.create_plugin(
cluster=self.cluster_db,
name='plugin_1',
attributes_metadata={'attributes': {'name': 'plugin_1'}},
package_version='4.0.0',
releases=releases
)
plugin2 = self.env.create_plugin(
cluster=self.cluster_db,
name='plugin_2',
attributes_metadata={'attributes': {'name': 'plugin_2'}},
package_version='4.0.0',
releases=releases
)
self.env.create_plugin(
cluster=self.cluster_db,
enabled=False,
name='plugin_3',
attributes_metadata={'attributes': {'name': 'plugin_3'}},
package_version='4.0.0',
releases=releases
)
self.env.create_node(
cluster_id=self.cluster_db.id,
roles=['compute']
)
plugins_data = [
{
'name': p.name,
'scripts': [{
'remote_url': p.master_scripts_path(self.cluster_db),
'local_path': p.slaves_scripts_path
}],
'repositories': [{
'type': 'deb',
'name': p.path_name,
'uri': p.repo_url(self.cluster_db),
'suite': '/',
'section': '',
'priority': 1100
}]
}
for p in six.moves.map(plugins.wrap_plugin, [plugin1, plugin2])
]
objects.Cluster.prepare_for_deployment(self.cluster_db)
serialized = self.serializer.serialize(
self.cluster_db, self.cluster_db.nodes)
self.assertIn('plugins', serialized['common'])
self.datadiff(plugins_data, serialized['common']['plugins'],
compare_sorted=True)
def test_serialize_with_customized(self):
objects.Cluster.prepare_for_deployment(self.cluster_db)
serialized = self.serializer.serialize(self.cluster_db, [self.node])
objects.Cluster.replace_deployment_info(self.cluster_db, serialized)
objects.Cluster.prepare_for_deployment(self.cluster_db)
cust_serialized = self.serializer.serialize(
self.cluster_db, [self.node])
self.assertEqual(serialized['common'], cust_serialized['common'])
self.assertItemsEqual(serialized['nodes'], cust_serialized['nodes'])
def test_provision_info_serialized(self):
objects.Cluster.prepare_for_deployment(self.cluster_db)
serialized = self.serializer.serialize(self.cluster_db, [self.node])
node_info = next(x for x in serialized['nodes']
if x['uid'] == self.node.uid)
self.assertIn('provision', node_info)
node_provision_info = node_info['provision']
# check that key options present in provision section
self.assertIn('ks_meta', node_provision_info)
self.assertIn('engine', serialized['common']['provision'])
provision_info = serialized['common']['provision']
self.assertIn('packages', provision_info)
self.assertIsInstance(provision_info['packages'], list)
def test_deleted_field_present_only_for_deleted_nodes(self):
objects.Cluster.prepare_for_deployment(self.cluster_db)
self.node.pending_deletion = True
serialized = self.serializer.serialize(self.cluster_db, [self.node])
node_info = next(x for x in serialized['nodes']
if x['uid'] == self.node.uid)
self.assertTrue(node_info['deleted'])
self.node.pending_deletion = False
serialized = self.serializer.serialize(self.cluster_db, [self.node])
node_info = next(x for x in serialized['nodes']
if x['uid'] == self.node.uid)
self.assertNotIn('deleted', node_info)
def test_plugin_node_attributes_serialization(self):
node = self.env.create_node(
cluster_id=self.cluster_db.id,
roles=['compute']
)
self.env.create_plugin(
name='test_plugin',
package_version='5.0.0',
cluster=self.cluster,
node_attributes_metadata={
'test_plugin_section': {
'attribute_a': {
'label': 'Node attribute A',
'value': 'attribute_a_val'
},
'attribute_b': {
'label': 'Node attribute B',
'value': 'attribute_b_val'
}
}
}
)
objects.Cluster.prepare_for_deployment(self.cluster_db)
serialized_for_astute = self.serializer.serialize(
self.cluster_db, [node])['common']['nodes'][0]
self.assertIn('test_plugin_section', serialized_for_astute)
self.assertDictEqual(
{
'attribute_a': 'attribute_a_val',
'attribute_b': 'attribute_b_val'
},
serialized_for_astute.get('test_plugin_section', {})
)
class TestDeploymentHASerializer90(
TestSerializer90Mixin,
test_orchestrator_serializer_80.TestDeploymentHASerializer80
):
def test_glance_properties(self):
self.check_no_murano_data()
def test_ceph_keys(self):
storage_attrs = self.serializer.get_common_attrs(
self.cluster
)['storage']
expected_keys = (
'fsid', 'mon_key', 'admin_key', 'bootstrap_osd_key', 'radosgw_key'
)
for ceph_key in expected_keys:
self.assertIn(ceph_key, storage_attrs)
def test_serialize_with_customized(self):
cluster = self.env.clusters[0]
serializer = self._get_serializer(cluster)
objects.Cluster.prepare_for_deployment(cluster)
serialized = serializer.serialize(cluster, cluster.nodes)
objects.Cluster.replace_deployment_info(cluster, serialized)
objects.Cluster.prepare_for_deployment(cluster)
cust_serialized = serializer.serialize(cluster, cluster.nodes)
self.assertEqual(serialized['common'], cust_serialized['common'])
self.assertItemsEqual(serialized['nodes'], cust_serialized['nodes'])
class TestDeploymentTasksSerialization90(
TestSerializer90Mixin,
test_orchestrator_serializer_80.TestDeploymentTasksSerialization80
):
pass
class TestMultiNodeGroupsSerialization90(
TestSerializer90Mixin,
test_orchestrator_serializer_80.TestMultiNodeGroupsSerialization80
):
pass
class TestNetworkTemplateSerializer90CompatibleWith80(
TestSerializer90Mixin,
test_orchestrator_serializer_80.
TestNetworkTemplateSerializer80CompatibleWith70
):
general_serializer = NeutronNetworkDeploymentSerializer90
template_serializer = NeutronNetworkTemplateSerializer90
def check_vendor_specific_is_not_set(self, use_net_template=False):
node = self.env.create_node(
cluster_id=self.cluster.id,
roles=['controller'], primary_tags=['controller']
)
objects.Cluster.set_network_template(
self.cluster,
self.net_template if use_net_template else None)
objects.Cluster.prepare_for_deployment(self.cluster)
serializer = deployment_serializers.get_serializer_for_cluster(
self.cluster)
net_serializer = serializer.get_net_provider_serializer(self.cluster)
nm = objects.Cluster.get_network_manager(self.cluster)
networks = nm.get_node_networks(node)
endpoints = net_serializer.generate_network_scheme(
node, networks)['endpoints']
for name in endpoints:
# Just 'provider_gateway' can be in 'vendor_specific'
if endpoints[name].get('vendor_specific'):
self.assertItemsEqual(['provider_gateway'],
endpoints[name]['vendor_specific'])
# This test is replaced as we have different attributes set in 9.0
def test_multiple_node_roles_network_metadata_attrs(self):
for node_data in self.serialized_for_astute:
self.assertItemsEqual(
node_data['network_metadata'], ['nodes', 'vips'])
nodes = node_data['network_metadata']['nodes']
for node_name, node_attrs in nodes.items():
self.assertTrue(
{'uid', 'fqdn', 'name', 'user_node_name', 'swift_zone',
'node_roles', 'network_roles',
'nova_cpu_pinning_enabled'}.issubset(node_attrs)
)
node = objects.Node.get_by_uid(node_attrs['uid'])
self.assertEqual(objects.Node.get_slave_name(node), node_name)
self.assertEqual(node_attrs['uid'], node.uid)
self.assertEqual(node_attrs['fqdn'],
objects.Node.get_node_fqdn(node))
self.assertEqual(node_attrs['name'], node_name)
self.assertEqual(node_attrs['user_node_name'], node.name)
self.assertEqual(node_attrs['swift_zone'], node.uid)
self.assertEqual(node_attrs['nova_cpu_pinning_enabled'], False)
@unittest2.skip(
"'nodes' key was removed from 9.0 version serializer output, "
"thus test bound to this data (that exists in parent test case class) "
"must be skipped"
)
def test_network_not_mapped_to_nics_w_template(self):
pass
class TestNetworkTemplateSerializer90(
TestSerializer90Mixin,
test_orchestrator_serializer_80.TestNetworkTemplateSerializer80
):
legacy_serializer = NeutronNetworkDeploymentSerializer90
template_serializer = NeutronNetworkTemplateSerializer90
def check_selective_gateway(self, use_net_template=False):
node = self.env.create_node(
cluster_id=self.cluster.id,
roles=['controller'], primary_tags=['controller']
)
objects.Cluster.set_network_template(
self.cluster,
self.net_template if use_net_template else None)
objects.Cluster.prepare_for_deployment(self.cluster)
serializer = deployment_serializers.get_serializer_for_cluster(
self.cluster)
net_serializer = serializer.get_net_provider_serializer(self.cluster)
nm = objects.Cluster.get_network_manager(self.cluster)
networks_list = nm.get_node_networks(node)
networks = {net['name']: net for net in networks_list}
endpoints = net_serializer.generate_network_scheme(
node, networks_list)['endpoints']
na = self.net_template[
'adv_net_template']['default']['network_assignments']
ep_net_map = {na[net_name]['ep']: net_name for net_name in na}
for name in endpoints:
if name not in ep_net_map:
self.assertNotIn('vendor_specific', endpoints[name])
continue
if networks[ep_net_map[name]].get('gateway') is None:
self.assertNotIn('vendor_specific', endpoints[name])
else:
self.assertIn('vendor_specific', endpoints[name])
self.assertEqual(
endpoints[name]['vendor_specific']['provider_gateway'],
networks[ep_net_map[name]]['gateway'])
def test_selective_gateway_in_deployment_serializer(self):
self.check_selective_gateway()
def test_selective_gateway_in_template_serializer(self):
self.check_selective_gateway(use_net_template=True)
class TestSerializeInterfaceDriversData90(
TestSerializer90Mixin,
test_orchestrator_serializer_80.TestSerializeInterfaceDriversData80
):
pass
class TestSriovSerialization90(
TestSerializer90Mixin,
test_orchestrator_serializer_80.BaseDeploymentSerializer
):
def setUp(self, *args):
super(TestSriovSerialization90, self).setUp()
self.cluster_db = self.env.create(
release_kwargs={'version': self.env_version},
cluster_kwargs={
'mode': consts.CLUSTER_MODES.ha_compact,
'net_provider': consts.CLUSTER_NET_PROVIDERS.neutron,
'net_segment_type': consts.NEUTRON_SEGMENT_TYPES.vlan,
'status': consts.CLUSTER_STATUSES.new},
)
self.env.create_nodes_w_interfaces_count(
nodes_count=1, if_count=3, cluster_id=self.cluster_db.id,
pending_roles=['compute'], pending_addition=True)
def serialize(self):
objects.Cluster.prepare_for_deployment(self.cluster_db)
serializer = self.create_serializer(self.cluster_db)
return serializer.serialize(self.cluster_db, self.env.nodes)
def test_nic_sriov_info_is_serialized(self):
for nic in self.env.nodes[0].nic_interfaces:
if not nic.assigned_networks_list:
nic_sriov = nic
nic.attributes['sriov'] = {
'enabled': {'value': True},
'numvfs': {'value': 8},
'physnet': {'value': 'new_physnet'}
}
nic.meta['sriov'] = {
'available': True,
'totalvfs': 8,
'pci_id': '1234:5678'
}
objects.NIC.update(
nic, {'attributes': nic.attributes, 'meta': nic.meta})
break
else:
self.fail('NIC without assigned networks was not found')
serialized = self.serialize()
node0 = serialized['nodes'][0]
common_attrs = serialized['common']
self.assertEqual(
common_attrs['quantum_settings']['supported_pci_vendor_devs'],
['1234:5678']
)
for trans in node0['network_scheme']['transformations']:
if trans.get('name') == nic_sriov.name:
self.assertEqual(
trans['vendor_specific'],
{
'sriov_numvfs': 8,
'physnet': 'new_physnet'
}
)
self.assertEqual(trans['provider'], 'sriov')
break
else:
self.fail('NIC with SR-IOV enabled was not found')