Merge "Add initial support of multi-rack for upgrades"
This commit is contained in:
commit
0ea51211d9
|
@ -328,20 +328,23 @@ class NetworkManager(object):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_assigned_vips(cls, cluster):
|
def get_assigned_vips(cls, cluster, network_names=None):
|
||||||
"""Return assigned VIPs mapped to names of network groups.
|
"""Return assigned VIPs mapped to IDs of network groups.
|
||||||
|
|
||||||
:param cluster: Is an instance of :class:`objects.Cluster`.
|
:param cluster: Is an instance of :class:`models.Cluster`.
|
||||||
:returns: A dict of VIPs mapped to names of network groups and
|
:param network_names: Filter return VIPs by names of networks if it is
|
||||||
they are grouped by the type.
|
not None.
|
||||||
|
:returns: A dict of VIPs mapped to IDs of network groups and
|
||||||
|
they are grouped by the name.
|
||||||
"""
|
"""
|
||||||
cluster_vips = \
|
cluster_vips = \
|
||||||
objects.IPAddrCollection.get_vips_by_cluster_id(cluster.id)
|
objects.IPAddrCollection.get_vips_by_cluster_id(cluster.id)
|
||||||
vips = defaultdict(dict)
|
vips = defaultdict(dict)
|
||||||
for vip in cluster_vips:
|
for vip in cluster_vips:
|
||||||
vips[vip.network_data.name][vip.vip_name] = objects.IPAddr.to_dict(
|
if network_names is not None and \
|
||||||
vip
|
vip.network_data.name not in network_names:
|
||||||
)
|
continue
|
||||||
|
vips[vip.network][vip.vip_name] = objects.IPAddr.to_dict(vip)
|
||||||
|
|
||||||
return vips
|
return vips
|
||||||
|
|
||||||
|
@ -354,8 +357,8 @@ class NetworkManager(object):
|
||||||
used for the upgrading procedure of clusters to copy VIPs from
|
used for the upgrading procedure of clusters to copy VIPs from
|
||||||
one cluster to the other.
|
one cluster to the other.
|
||||||
|
|
||||||
:param cluster: Is an instance of :class:`objects.Cluster`.
|
:param cluster: Is an instance of :class:`models.Cluster`.
|
||||||
:param vips: A dict of VIPs mapped to names of network groups
|
:param vips: A dict of VIPs mapped to IDs of network groups
|
||||||
that are grouped by the type.
|
that are grouped by the type.
|
||||||
:raises: errors.AssignIPError
|
:raises: errors.AssignIPError
|
||||||
"""
|
"""
|
||||||
|
@ -363,43 +366,41 @@ class NetworkManager(object):
|
||||||
objects.IPAddrCollection.get_vips_by_cluster_id(cluster.id)
|
objects.IPAddrCollection.get_vips_by_cluster_id(cluster.id)
|
||||||
assigned_vips = defaultdict(dict)
|
assigned_vips = defaultdict(dict)
|
||||||
for vip in cluster_vips:
|
for vip in cluster_vips:
|
||||||
assigned_vips[vip.network_data.name][vip.vip_name] = vip
|
assigned_vips[vip.network][vip.vip_name] = vip
|
||||||
for net_group in cluster.network_groups:
|
for net_group in cluster.network_groups:
|
||||||
if net_group.name not in vips:
|
if net_group.id not in vips:
|
||||||
continue
|
continue
|
||||||
assigned_vips_by_type = assigned_vips.get(net_group.name, {})
|
assigned_vips_for_net = assigned_vips.get(net_group.id, {})
|
||||||
for vip_name, vip_dict in six.iteritems(vips[net_group.name]):
|
for vip_name, vip in six.iteritems(vips[net_group.id]):
|
||||||
if not cls.check_ip_belongs_to_net(
|
if not cls.check_ip_belongs_to_net(vip['ip_addr'], net_group):
|
||||||
vip_dict['ip_addr'], net_group):
|
|
||||||
ranges = [(rng.first, rng.last)
|
ranges = [(rng.first, rng.last)
|
||||||
for rng in net_group.ip_ranges]
|
for rng in net_group.ip_ranges]
|
||||||
raise errors.AssignIPError(
|
raise errors.AssignIPError(
|
||||||
"Cannot assign VIP with the address '{ip_addr}' "
|
("Cannot assign VIP with the address '{ip_addr}' "
|
||||||
"because it does not belong to the network {net_id} - "
|
"because it does not belong to the network {net_id} "
|
||||||
"'{net_name}' with ranges {net_ranges} of the cluster "
|
"- '{net_name}' with ranges {net_ranges} and CIDR "
|
||||||
"'{cluster_id}'."
|
"{net_cidr} of the cluster '{cluster_id}'.").format(
|
||||||
.format(
|
ip_addr=vip['ip_addr'],
|
||||||
ip_addr=vip_dict['ip_addr'],
|
|
||||||
net_id=net_group.id,
|
net_id=net_group.id,
|
||||||
net_name=net_group.name,
|
net_name=net_group.name,
|
||||||
net_ranges=ranges,
|
net_ranges=ranges,
|
||||||
cluster_id=cluster.id,
|
net_cidr=net_group.cidr,
|
||||||
)
|
cluster_id=cluster.id)
|
||||||
)
|
)
|
||||||
if vip_name in assigned_vips_by_type:
|
if vip_name in assigned_vips_for_net:
|
||||||
assigned_vip = assigned_vips_by_type[vip_name]
|
assigned_vip = assigned_vips_for_net[vip_name]
|
||||||
objects.IPAddr.update(assigned_vip, {
|
objects.IPAddr.update(assigned_vip, {
|
||||||
'ip_addr': vip_dict['ip_addr'],
|
'ip_addr': vip['ip_addr'],
|
||||||
'vip_namespace': vip_dict['vip_namespace'],
|
'vip_namespace': vip['vip_namespace'],
|
||||||
'is_user_defined': vip_dict['is_user_defined'],
|
'is_user_defined': vip['is_user_defined'],
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
objects.IPAddr.create({
|
objects.IPAddr.create({
|
||||||
'network': net_group.id,
|
'network': net_group.id,
|
||||||
'ip_addr': vip_dict['ip_addr'],
|
'ip_addr': vip['ip_addr'],
|
||||||
'vip_name': vip_name,
|
'vip_name': vip_name,
|
||||||
'vip_namespace': vip_dict['vip_namespace'],
|
'vip_namespace': vip['vip_namespace'],
|
||||||
'is_user_defined': vip_dict['is_user_defined'],
|
'is_user_defined': vip['is_user_defined'],
|
||||||
})
|
})
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
@ -70,6 +70,27 @@ def _convert_vips(vips):
|
||||||
return vips
|
return vips
|
||||||
|
|
||||||
|
|
||||||
|
def _set_name(vips):
|
||||||
|
"""Return VIPs mapped to names of network groups.
|
||||||
|
|
||||||
|
:param vips: A dict of VIPs mapped to IDs of network groups.
|
||||||
|
:returns: A dict of VIPs mapped to names of network groups.
|
||||||
|
"""
|
||||||
|
return {objects.NetworkGroup.get_by_uid(id).name: vip
|
||||||
|
for id, vip in six.iteritems(vips)}
|
||||||
|
|
||||||
|
|
||||||
|
def _set_id(vips, cluster):
|
||||||
|
"""Return VIPs mapped to IDs of network groups.
|
||||||
|
|
||||||
|
:param vips: A dict of VIPs mapped to names of network groups.
|
||||||
|
:param cluster: Is an instance of :class:`models.Cluster`.
|
||||||
|
:returns: A dict of VIPs mapped to IDs of network groups.
|
||||||
|
"""
|
||||||
|
return {ng.id: vips[ng.name]
|
||||||
|
for ng in cluster.network_groups if ng.name in vips}
|
||||||
|
|
||||||
|
|
||||||
def _make_vip(**kwargs):
|
def _make_vip(**kwargs):
|
||||||
"""Represents a VIP as a dict with some default values."""
|
"""Represents a VIP as a dict with some default values."""
|
||||||
data = {
|
data = {
|
||||||
|
@ -294,7 +315,7 @@ class TestNetworkManager(BaseIntegrationTest):
|
||||||
|
|
||||||
needed_vip_ip = [
|
needed_vip_ip = [
|
||||||
vip_info for network, vip_info in six.iteritems(vips_after)
|
vip_info for network, vip_info in six.iteritems(vips_after)
|
||||||
if vip.network_data.name == network and vip.vip_name in vip_info
|
if vip.network_data.id == network and vip.vip_name in vip_info
|
||||||
][0][vip.vip_name]['ip_addr']
|
][0][vip.vip_name]['ip_addr']
|
||||||
|
|
||||||
self.assertEqual(needed_vip_ip, ip_before)
|
self.assertEqual(needed_vip_ip, ip_before)
|
||||||
|
@ -756,7 +777,7 @@ class TestNetworkManager(BaseIntegrationTest):
|
||||||
cluster = self.create_env_w_controller()
|
cluster = self.create_env_w_controller()
|
||||||
self.env.create_ip_addrs_by_rules(cluster, vips_to_create)
|
self.env.create_ip_addrs_by_rules(cluster, vips_to_create)
|
||||||
vips = self.env.network_manager.get_assigned_vips(cluster)
|
vips = self.env.network_manager.get_assigned_vips(cluster)
|
||||||
self.assertEqual(vips_to_create, _convert_vips(vips))
|
self.assertEqual(vips_to_create, _set_name(_convert_vips(vips)))
|
||||||
|
|
||||||
def test_assign_given_vips_for_net_groups(self):
|
def test_assign_given_vips_for_net_groups(self):
|
||||||
haproxy = consts.NETWORK_VIP_NAMES_V6_1.haproxy
|
haproxy = consts.NETWORK_VIP_NAMES_V6_1.haproxy
|
||||||
|
@ -772,6 +793,7 @@ class TestNetworkManager(BaseIntegrationTest):
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cluster = self.env.create_cluster(api=False)
|
cluster = self.env.create_cluster(api=False)
|
||||||
|
vips_to_assign = _set_id(vips_to_assign, cluster)
|
||||||
self.env.network_manager.assign_given_vips_for_net_groups(
|
self.env.network_manager.assign_given_vips_for_net_groups(
|
||||||
cluster, vips_to_assign)
|
cluster, vips_to_assign)
|
||||||
vips = self.env.network_manager.get_assigned_vips(cluster)
|
vips = self.env.network_manager.get_assigned_vips(cluster)
|
||||||
|
@ -796,6 +818,7 @@ class TestNetworkManager(BaseIntegrationTest):
|
||||||
}
|
}
|
||||||
expected_msg_regexp = "^Cannot assign VIP with the address '10.10.0.1'"
|
expected_msg_regexp = "^Cannot assign VIP with the address '10.10.0.1'"
|
||||||
cluster = self.env.create_cluster(api=False)
|
cluster = self.env.create_cluster(api=False)
|
||||||
|
vips_to_assign = _set_id(vips_to_assign, cluster)
|
||||||
with self.assertRaisesRegexp(errors.AssignIPError,
|
with self.assertRaisesRegexp(errors.AssignIPError,
|
||||||
expected_msg_regexp):
|
expected_msg_regexp):
|
||||||
self.env.network_manager.assign_given_vips_for_net_groups(
|
self.env.network_manager.assign_given_vips_for_net_groups(
|
||||||
|
@ -1577,7 +1600,7 @@ class TestNeutronManager70(BaseIntegrationTest):
|
||||||
'public': '172.16.0.3',
|
'public': '172.16.0.3',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
self.assertEqual(expected_vips, _convert_vips(vips))
|
self.assertEqual(expected_vips, _set_name(_convert_vips(vips)))
|
||||||
|
|
||||||
def test_assign_given_vips_for_net_groups(self):
|
def test_assign_given_vips_for_net_groups(self):
|
||||||
# rewrite VIPs allocated on creation of cluster
|
# rewrite VIPs allocated on creation of cluster
|
||||||
|
@ -1591,6 +1614,7 @@ class TestNeutronManager70(BaseIntegrationTest):
|
||||||
'public': _make_vip(ip_addr='172.16.0.5'),
|
'public': _make_vip(ip_addr='172.16.0.5'),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
vips_to_assign = _set_id(vips_to_assign, self.cluster)
|
||||||
self.net_manager.assign_given_vips_for_net_groups(
|
self.net_manager.assign_given_vips_for_net_groups(
|
||||||
self.cluster, vips_to_assign)
|
self.cluster, vips_to_assign)
|
||||||
vips = self.net_manager.get_assigned_vips(self.cluster)
|
vips = self.net_manager.get_assigned_vips(self.cluster)
|
||||||
|
|
|
@ -432,13 +432,19 @@ class Node(NailgunObject):
|
||||||
@classmethod
|
@classmethod
|
||||||
def assign_group(cls, instance):
|
def assign_group(cls, instance):
|
||||||
if instance.group_id is None and instance.ip:
|
if instance.group_id is None and instance.ip:
|
||||||
admin_ngs = db().query(models.NetworkGroup).filter_by(
|
query = db().query(models.NetworkGroup.cidr,
|
||||||
name="fuelweb_admin")
|
models.NetworkGroup.group_id).join(
|
||||||
|
models.NodeGroup.networks
|
||||||
|
).filter(
|
||||||
|
models.NetworkGroup.name == "fuelweb_admin",
|
||||||
|
models.NetworkGroup.group_id is not None,
|
||||||
|
# Only node group of the same cluster can be selected.
|
||||||
|
models.NodeGroup.cluster_id == instance.cluster_id
|
||||||
|
)
|
||||||
ip = IPAddress(instance.ip)
|
ip = IPAddress(instance.ip)
|
||||||
|
for cidr, group_id in query:
|
||||||
for ng in admin_ngs:
|
if ip in IPNetwork(cidr):
|
||||||
if ip in IPNetwork(ng.cidr):
|
instance.group_id = group_id
|
||||||
instance.group_id = ng.group_id
|
|
||||||
break
|
break
|
||||||
|
|
||||||
if not instance.group_id:
|
if not instance.group_id:
|
||||||
|
|
|
@ -21,6 +21,9 @@ import mock
|
||||||
|
|
||||||
from itertools import cycle
|
from itertools import cycle
|
||||||
from itertools import ifilter
|
from itertools import ifilter
|
||||||
|
|
||||||
|
from nailgun.db import db
|
||||||
|
from nailgun.db.sqlalchemy import models
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from sqlalchemy import inspect as sqlalchemy_inspect
|
from sqlalchemy import inspect as sqlalchemy_inspect
|
||||||
|
@ -210,6 +213,31 @@ class TestNodeObject(BaseIntegrationTest):
|
||||||
self.assertItemsEqual(roles, node.pending_roles)
|
self.assertItemsEqual(roles, node.pending_roles)
|
||||||
self.assertEqual(node.attributes, cluster.release.node_attributes)
|
self.assertEqual(node.attributes, cluster.release.node_attributes)
|
||||||
|
|
||||||
|
def test_assign_group(self):
|
||||||
|
cluster = self.env.create(
|
||||||
|
cluster_kwargs={'api': False},
|
||||||
|
nodes_kwargs=[{'role': 'controller'}] * 3)
|
||||||
|
new_cluster = self.env.create_cluster(api=False)
|
||||||
|
data = {
|
||||||
|
'name': 'custom',
|
||||||
|
'cluster_id': new_cluster.id
|
||||||
|
}
|
||||||
|
new_group = objects.NodeGroup.create(data)
|
||||||
|
admin_group_id = db().query(
|
||||||
|
models.NetworkGroup.id
|
||||||
|
).join(
|
||||||
|
models.NetworkGroup.nodegroup
|
||||||
|
).filter(
|
||||||
|
models.NodeGroup.cluster_id == new_group.cluster_id,
|
||||||
|
models.NetworkGroup.name == consts.NETWORKS.fuelweb_admin
|
||||||
|
).first()
|
||||||
|
admin_group = objects.NetworkGroup.get_by_uid(admin_group_id)
|
||||||
|
admin_group.cidr = '10.20.0.0/24'
|
||||||
|
node = cluster.nodes[0]
|
||||||
|
roles = node.roles
|
||||||
|
objects.Node.update_cluster_assignment(node, new_cluster, [], roles)
|
||||||
|
self.assertEqual(new_group.id, node.group_id)
|
||||||
|
|
||||||
def test_update_cluster_assignment_with_templates_80(self):
|
def test_update_cluster_assignment_with_templates_80(self):
|
||||||
cluster = self.env.create(
|
cluster = self.env.create(
|
||||||
cluster_kwargs={'api': False},
|
cluster_kwargs={'api': False},
|
||||||
|
|
Loading…
Reference in New Issue