Fix checking of public IPs count

Fixed CheckBeforeDeploymentTask._check_network() method to properly
compare quantity of public IPs and nodes that require them.
Tests added.

Closes-Bug: 1376426

Change-Id: I9b3278286a9d67aff784e5c241db1dc299a2f94e
This commit is contained in:
Aleksey Kasatkin 2014-11-11 18:12:33 +02:00
parent 748b8b8ef3
commit df80eb24b1
6 changed files with 129 additions and 28 deletions

View File

@ -514,6 +514,23 @@ class Cluster(NailgunObject):
def get_creds(cls, instance):
return instance.attributes.editable['access']
@classmethod
def should_assign_public_to_all_nodes(cls, instance):
"""Determine whether Public network is to be assigned to all nodes in
this cluster.
:param instance: cluster instance
:returns: True when Public network is to be assigned to all nodes
"""
if instance.net_provider == \
consts.CLUSTER_NET_PROVIDERS.nova_network:
return True
assignment = instance.attributes.editable.get(
'public_network_assignment')
if not assignment or assignment['assign_to_all_nodes']['value']:
return True
return False
class ClusterCollection(NailgunCollection):
"""Cluster collection

View File

@ -152,12 +152,7 @@ class Node(NailgunObject):
:param instance: Node DB instance
:returns: True when node has Public network
"""
if instance.cluster.net_provider == \
consts.CLUSTER_NET_PROVIDERS.nova_network:
return True
assignment = instance.cluster.attributes.editable.get(
'public_network_assignment')
if not assignment or assignment['assign_to_all_nodes']['value']:
if Cluster.should_assign_public_to_all_nodes(instance.cluster):
return True
ctrl = set(['primary-controller', 'controller', 'zabbix-server'])
if ctrl & (set(instance.roles) or set(instance.pending_roles)):
@ -799,3 +794,7 @@ class NodeCollection(NailgunCollection):
instances_ids = [instance.id for instance in instances]
q = cls.filter_by_list(None, 'id', instances_ids, order_by='id')
return cls.lock_for_update(q).all()
@classmethod
def get_by_group_id(cls, group_id):
return cls.filter_by(None, group_id=group_id)

View File

@ -575,7 +575,7 @@ class CheckBeforeDeploymentTask(object):
cls._check_disks(task)
cls._check_ceph(task)
cls._check_volumes(task)
cls._check_network(task)
cls._check_public_network(task)
@classmethod
def _check_nodes_are_online(cls, task):
@ -687,17 +687,26 @@ class CheckBeforeDeploymentTask(object):
(osd_count, osd_pool_size))
@classmethod
def _check_network(cls, task):
nodes_count = len(task.cluster.nodes)
def _check_public_network(cls, task):
all_public = \
objects.Cluster.should_assign_public_to_all_nodes(task.cluster)
public_network = filter(
public_networks = filter(
lambda ng: ng.name == 'public',
task.cluster.network_groups)[0]
public_network_size = cls.__network_size(public_network)
task.cluster.network_groups)
if public_network_size < nodes_count:
error_message = cls.__format_network_error(nodes_count)
raise errors.NetworkCheckError(error_message)
for public in public_networks:
nodes = objects.NodeCollection.get_by_group_id(public.group_id)
if all_public:
nodes_count = nodes.count()
else:
nodes_count = sum(int(objects.Node.should_have_public(node))
for node in nodes)
vip_count = 0 if not task.cluster.is_ha_mode else \
int(any('controller' in node.all_roles for node in nodes))
if cls.__network_size(public) < nodes_count + vip_count:
error_message = cls.__format_network_error(public, nodes_count)
raise errors.NetworkCheckError(error_message)
@classmethod
def __network_size(cls, network):
@ -705,9 +714,9 @@ class CheckBeforeDeploymentTask(object):
for ip_range in network.ip_ranges)
@classmethod
def __format_network_error(cls, nodes_count):
return 'Not enough IP addresses. Public network must have at least '\
'{nodes_count} IP addresses '.format(nodes_count=nodes_count) + \
def __format_network_error(cls, public, nodes_count):
return 'Not enough IP addresses. Public network {0} must have ' \
'at least {1} IP addresses '.format(public.cidr, nodes_count) + \
'for the current environment.'

View File

@ -1044,8 +1044,8 @@ class TestHandlers(BaseIntegrationTest):
self.assertEqual(task.status, 'error')
self.assertEqual(
task.message,
'Not enough IP addresses. Public network must have at least '
'3 IP addresses for the current environment.')
'Not enough IP addresses. Public network 172.16.0.0/24 must have '
'at least 3 IP addresses for the current environment.')
def test_occurs_error_not_enough_ip_addresses(self):
self.env.create(
@ -1082,8 +1082,8 @@ class TestHandlers(BaseIntegrationTest):
self.assertEqual(task.status, 'error')
self.assertEqual(
task.message,
'Not enough IP addresses. Public network must have at least '
'3 IP addresses for the current environment.')
'Not enough IP addresses. Public network 220.0.1.0/24 must have '
'at least 3 IP addresses for the current environment.')
def test_occurs_error_not_enough_free_space(self):
meta = self.env.default_metadata()

View File

@ -234,10 +234,11 @@ class TestNodeObject(BaseIntegrationTest):
attrs['public_network_assignment']['assign_to_all_nodes']['value'],
False
)
self.assertFalse(
objects.Cluster.should_assign_public_to_all_nodes(cluster))
nodes_w_public_count = 0
for node in self.env.nodes:
nodes_w_public_count += int(objects.Node.should_have_public(node))
nodes_w_public_count = sum(int(objects.Node.should_have_public(node))
for node in self.env.nodes)
self.assertEqual(nodes_w_public_count, 2)
attrs['public_network_assignment']['assign_to_all_nodes']['value'] = \
@ -250,10 +251,11 @@ class TestNodeObject(BaseIntegrationTest):
headers=self.default_headers
)
self.assertEqual(200, resp.status_code)
self.assertTrue(
objects.Cluster.should_assign_public_to_all_nodes(cluster))
nodes_w_public_count = 0
for node in self.env.nodes:
nodes_w_public_count += int(objects.Node.should_have_public(node))
nodes_w_public_count = sum(int(objects.Node.should_have_public(node))
for node in self.env.nodes)
self.assertEqual(nodes_w_public_count, 5)
def test_removing_from_cluster(self):

View File

@ -19,8 +19,10 @@ from nailgun import consts
from nailgun.db.sqlalchemy.models import Task
from nailgun.errors import errors
from nailgun import objects
from nailgun.openstack.common import jsonutils
from nailgun.task.task import CheckBeforeDeploymentTask
from nailgun.test.base import BaseTestCase
from nailgun.test.base import reverse
from nailgun.volumes.manager import VolumeManager
@ -163,6 +165,10 @@ class TestCheckBeforeDeploymentTask(BaseTestCase):
def setUp(self):
super(TestCheckBeforeDeploymentTask, self).setUp()
self.env.create(
cluster_kwargs={
'net_provider': 'neutron',
'net_segment_type': 'gre'
},
nodes_kwargs=[{'roles': ['controller']}])
self.env.create_node()
@ -282,3 +288,71 @@ class TestCheckBeforeDeploymentTask(BaseTestCase):
errors.NotEnoughControllers,
CheckBeforeDeploymentTask._check_controllers_count,
self.task)
def find_net_by_name(self, nets, name):
for net in nets['networks']:
if net['name'] == name:
return net
def test_check_public_networks(self):
cluster = self.env.clusters[0]
self.env.create_nodes(
2, api=True, roles=['controller'], cluster_id=cluster.id)
self.env.create_nodes(
2, api=True, roles=['compute'], cluster_id=cluster.id)
# we have 3 controllers now
self.assertEqual(
sum('controller' in n.all_roles for n in self.env.nodes),
3
)
attrs = cluster.attributes.editable
self.assertEqual(
attrs['public_network_assignment']['assign_to_all_nodes']['value'],
False
)
self.assertFalse(
objects.Cluster.should_assign_public_to_all_nodes(cluster))
resp = self.env.neutron_networks_get(cluster.id)
nets = resp.json_body
# enough IPs for 3 nodes but VIP
self.find_net_by_name(nets, 'public')['ip_ranges'] = \
[["172.16.0.2", "172.16.0.4"]]
resp = self.env.neutron_networks_put(cluster.id, nets)
self.assertEqual(resp.status_code, 202)
self.assertRaises(
errors.NetworkCheckError,
CheckBeforeDeploymentTask._check_public_network,
self.task)
# enough IPs for 3 nodes and VIP
self.find_net_by_name(nets, 'public')['ip_ranges'] = \
[["172.16.0.2", "172.16.0.5"]]
resp = self.env.neutron_networks_put(cluster.id, nets)
self.assertEqual(resp.status_code, 202)
self.assertNotRaises(
errors.NetworkCheckError,
CheckBeforeDeploymentTask._check_public_network,
self.task)
attrs['public_network_assignment']['assign_to_all_nodes']['value'] = \
True
resp = self.app.patch(
reverse(
'ClusterAttributesHandler',
kwargs={'cluster_id': cluster.id}),
params=jsonutils.dumps({'editable': attrs}),
headers=self.default_headers
)
self.assertEqual(200, resp.status_code)
self.assertTrue(
objects.Cluster.should_assign_public_to_all_nodes(cluster))
self.assertRaises(
errors.NetworkCheckError,
CheckBeforeDeploymentTask._check_public_network,
self.task)