Add initial support of multi-rack for upgrades
* netgroups mapping was changed (additional argument for the mapping was added - name of node group) * copying of node group during cluster cloning was added Depends-On: I2638279371e91f15090c782fc5fdbb434a2e85f8 Partial-bug: #1612297 Change-Id: Ib1689d7b6d673c0d78434dd047a7ebc520c232e7 Co-Authored-By: Ryan Moe <rmoe@mirantis.com> Co-Authored-By: Andrew Woodward <awoodward@mirantis.com> Co-Authored-By: Ilya Kharin <akscram@gmail.com>
This commit is contained in:
parent
4136bc9aed
commit
e2b9dbf1ca
|
@ -140,11 +140,8 @@ class CopyVIPsHandler(base.BaseHandler):
|
||||||
self.checked_data(cluster=cluster, relation=relation)
|
self.checked_data(cluster=cluster, relation=relation)
|
||||||
|
|
||||||
# get original cluster object and create adapter with it
|
# get original cluster object and create adapter with it
|
||||||
orig_cluster_adapter = \
|
orig_cluster_adapter = adapters.NailgunClusterAdapter.get_by_uid(
|
||||||
adapters.NailgunClusterAdapter(
|
relation.orig_cluster_id)
|
||||||
adapters.NailgunClusterAdapter.get_by_uid(
|
|
||||||
relation.orig_cluster_id)
|
|
||||||
)
|
|
||||||
|
|
||||||
seed_cluster_adapter = adapters.NailgunClusterAdapter(cluster)
|
seed_cluster_adapter = adapters.NailgunClusterAdapter(cluster)
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,10 @@ class NailgunClusterAdapter(object):
|
||||||
def name(self):
|
def name(self):
|
||||||
return self.cluster.name
|
return self.cluster.name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def node_groups(self):
|
||||||
|
return self.cluster.node_groups
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def net_provider(self):
|
def net_provider(self):
|
||||||
return self.cluster.net_provider
|
return self.cluster.net_provider
|
||||||
|
@ -135,8 +139,9 @@ class NailgunNetworkManager(object):
|
||||||
def update(self, network_configuration):
|
def update(self, network_configuration):
|
||||||
self.net_manager.update(self.cluster, network_configuration)
|
self.net_manager.update(self.cluster, network_configuration)
|
||||||
|
|
||||||
def get_assigned_vips(self):
|
def get_assigned_vips(self, network_names=None):
|
||||||
return self.net_manager.get_assigned_vips(self.cluster)
|
return self.net_manager.get_assigned_vips(
|
||||||
|
self.cluster, network_names=network_names)
|
||||||
|
|
||||||
def assign_vips_for_net_groups(self):
|
def assign_vips_for_net_groups(self):
|
||||||
return self.net_manager.assign_vips_for_net_groups(self.cluster)
|
return self.net_manager.assign_vips_for_net_groups(self.cluster)
|
||||||
|
@ -230,3 +235,11 @@ class NailgunNetworkGroupAdapter(object):
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
return self.network_group.name
|
return self.network_group.name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def nodegroup(self):
|
||||||
|
return self.network_group.nodegroup
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_by_uid(cls, ng_id):
|
||||||
|
return objects.NetworkGroup.get_by_uid(ng_id)
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
import unittest
|
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
|
@ -227,7 +226,7 @@ class TestNodeReassignHandler(base.BaseIntegrationTest):
|
||||||
|
|
||||||
|
|
||||||
class TestCopyVipsHandler(tests_base.BaseCloneClusterTest):
|
class TestCopyVipsHandler(tests_base.BaseCloneClusterTest):
|
||||||
@unittest.skip("Skip test regarding vips")
|
|
||||||
def test_copy_vips(self):
|
def test_copy_vips(self):
|
||||||
node_db = self.env.create_node(cluster_id=self.src_cluster.id,
|
node_db = self.env.create_node(cluster_id=self.src_cluster.id,
|
||||||
roles=["controller"])
|
roles=["controller"])
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
from distutils import version
|
from distutils import version
|
||||||
import unittest
|
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
from nailgun.test import base as nailgun_test_base
|
from nailgun.test import base as nailgun_test_base
|
||||||
|
@ -249,33 +248,32 @@ class TestClusterTransformers(nailgun_test_base.BaseUnitTest):
|
||||||
class TestVipTransformers(nailgun_test_base.BaseUnitTest):
|
class TestVipTransformers(nailgun_test_base.BaseUnitTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
ip = '0.0.0.0'
|
ip = '0.0.0.0'
|
||||||
|
|
||||||
self.data = {
|
self.data = {
|
||||||
'management': {
|
1: {
|
||||||
'haproxy': ip,
|
'haproxy': ip,
|
||||||
'vrouter': ip,
|
'vrouter': ip,
|
||||||
'test': ip,
|
'test': ip,
|
||||||
},
|
},
|
||||||
'public': {
|
2: {
|
||||||
'haproxy': ip,
|
'haproxy': ip,
|
||||||
'vrouter': ip,
|
'vrouter': ip,
|
||||||
'test': ip,
|
'test': ip,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.mapping = {1: 'management', 2: 'public'}
|
||||||
|
|
||||||
@unittest.skip("Skip test regarding vips")
|
|
||||||
def test_vip_transform(self):
|
def test_vip_transform(self):
|
||||||
ip = '0.0.0.0'
|
ip = '0.0.0.0'
|
||||||
|
|
||||||
data = vip.transform_vips(self.data)
|
data = vip.transform_vips((self.data, self.mapping))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
data, {
|
data, ({
|
||||||
'management': {
|
1: {
|
||||||
'management': ip,
|
'management': ip,
|
||||||
'vrouter': ip,
|
'vrouter': ip,
|
||||||
},
|
},
|
||||||
'public': {
|
2: {
|
||||||
'public': ip,
|
'public': ip,
|
||||||
'vrouter_pub': ip,
|
'vrouter_pub': ip,
|
||||||
}}
|
}}, {1: 'management', 2: 'public'})
|
||||||
)
|
)
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
import unittest
|
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
@ -146,7 +145,6 @@ class TestUpgradeHelperCloneCluster(base_tests.BaseCloneClusterTest):
|
||||||
self.assertEqual(public_net['ip_ranges'],
|
self.assertEqual(public_net['ip_ranges'],
|
||||||
self.public_net_data['ip_ranges'])
|
self.public_net_data['ip_ranges'])
|
||||||
|
|
||||||
@unittest.skip("Skip test regarding vips")
|
|
||||||
def test_copy_vips(self):
|
def test_copy_vips(self):
|
||||||
# save network information before node reassignment to seed cluster
|
# save network information before node reassignment to seed cluster
|
||||||
# as after that no VIP will be allocated/serialized due to
|
# as after that no VIP will be allocated/serialized due to
|
||||||
|
|
|
@ -42,17 +42,17 @@ def transform_vips(data):
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
renamed_vips = collections.defaultdict(dict)
|
renamed_vips = collections.defaultdict(dict)
|
||||||
for ng_name, vips_obj in data.items():
|
vips, id_name_mapping = data
|
||||||
|
for ng_id, vips_obj in vips.items():
|
||||||
ng_vip_rules = rename_vip_rules[ng_name]
|
ng_vip_rules = rename_vip_rules[id_name_mapping[ng_id]]
|
||||||
for vip_name, vip_addr in vips_obj.items():
|
for vip_name, vip_addr in vips_obj.items():
|
||||||
if vip_name not in ng_vip_rules:
|
if vip_name not in ng_vip_rules:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
new_vip_name = ng_vip_rules[vip_name]
|
new_vip_name = ng_vip_rules[vip_name]
|
||||||
renamed_vips[ng_name][new_vip_name] = vip_addr
|
renamed_vips[ng_id][new_vip_name] = vip_addr
|
||||||
|
|
||||||
return renamed_vips
|
return renamed_vips, id_name_mapping
|
||||||
|
|
||||||
|
|
||||||
class Manager(transformations.Manager):
|
class Manager(transformations.Manager):
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
|
import collections
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from nailgun import consts
|
from nailgun import consts
|
||||||
|
@ -47,13 +49,22 @@ def merge_attributes(a, b):
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
|
def get_net_key(net):
|
||||||
|
group_name = None
|
||||||
|
if net["group_id"]:
|
||||||
|
group_name = objects.NodeGroup.get_by_uid(net["group_id"]).name
|
||||||
|
return (net["name"], group_name)
|
||||||
|
|
||||||
|
|
||||||
def merge_nets(a, b):
|
def merge_nets(a, b):
|
||||||
new_settings = copy.deepcopy(b)
|
new_settings = copy.deepcopy(b)
|
||||||
source_networks = dict((n["name"], n) for n in a["networks"])
|
source_networks = dict((get_net_key(net), net) for net in a["networks"])
|
||||||
|
|
||||||
for net in new_settings["networks"]:
|
for net in new_settings["networks"]:
|
||||||
if net["name"] not in source_networks:
|
net_key = get_net_key(net)
|
||||||
|
if net_key not in source_networks:
|
||||||
continue
|
continue
|
||||||
source_net = source_networks[net["name"]]
|
source_net = source_networks[net_key]
|
||||||
for key, value in six.iteritems(net):
|
for key, value in six.iteritems(net):
|
||||||
if (key not in ("cluster_id", "id", "meta", "group_id") and
|
if (key not in ("cluster_id", "id", "meta", "group_id") and
|
||||||
key in source_net):
|
key in source_net):
|
||||||
|
@ -84,6 +95,7 @@ class UpgradeHelper(object):
|
||||||
|
|
||||||
new_cluster = cls.create_cluster_clone(orig_cluster, data)
|
new_cluster = cls.create_cluster_clone(orig_cluster, data)
|
||||||
cls.copy_attributes(orig_cluster, new_cluster)
|
cls.copy_attributes(orig_cluster, new_cluster)
|
||||||
|
cls.copy_node_groups(orig_cluster, new_cluster)
|
||||||
cls.copy_network_config(orig_cluster, new_cluster)
|
cls.copy_network_config(orig_cluster, new_cluster)
|
||||||
relations.UpgradeRelationObject.create_relation(orig_cluster.id,
|
relations.UpgradeRelationObject.create_relation(orig_cluster.id,
|
||||||
new_cluster.id)
|
new_cluster.id)
|
||||||
|
@ -124,6 +136,18 @@ class UpgradeHelper(object):
|
||||||
attrs = new_cluster.attributes
|
attrs = new_cluster.attributes
|
||||||
attrs['editable']['provision']['method']['value'] = 'image'
|
attrs['editable']['provision']['method']['value'] = 'image'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def copy_node_groups(cls, orig_cluster, new_cluster):
|
||||||
|
for ng in orig_cluster.node_groups:
|
||||||
|
if getattr(ng, 'is_default', False) or ng.name == 'default':
|
||||||
|
continue
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'name': ng.name,
|
||||||
|
'cluster_id': new_cluster.id
|
||||||
|
}
|
||||||
|
objects.NodeGroup.create(data)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def copy_network_config(cls, orig_cluster, new_cluster):
|
def copy_network_config(cls, orig_cluster, new_cluster):
|
||||||
nets_serializer = cls.network_serializers[orig_cluster.net_provider]
|
nets_serializer = cls.network_serializers[orig_cluster.net_provider]
|
||||||
|
@ -140,19 +164,37 @@ class UpgradeHelper(object):
|
||||||
orig_net_manager = orig_cluster.get_network_manager()
|
orig_net_manager = orig_cluster.get_network_manager()
|
||||||
new_net_manager = new_cluster.get_network_manager()
|
new_net_manager = new_cluster.get_network_manager()
|
||||||
|
|
||||||
vips = {}
|
vips = orig_net_manager.get_assigned_vips(
|
||||||
assigned_vips = orig_net_manager.get_assigned_vips()
|
network_names=(consts.NETWORKS.public, consts.NETWORKS.management))
|
||||||
for ng_name in (consts.NETWORKS.public, consts.NETWORKS.management):
|
|
||||||
vips[ng_name] = assigned_vips[ng_name]
|
|
||||||
|
|
||||||
vips = cls.vip_transformations.apply(
|
netgroups_id_mapping = cls.get_netgroups_id_mapping(orig_cluster,
|
||||||
|
new_cluster)
|
||||||
|
new_vips = cls.reassociate_vips(vips, netgroups_id_mapping)
|
||||||
|
id_name_vips_mapping = cls.get_id_name_vips_mapping(new_vips)
|
||||||
|
new_vips, id_name_vips_mapping = cls.vip_transformations.apply(
|
||||||
orig_cluster.release.environment_version,
|
orig_cluster.release.environment_version,
|
||||||
new_cluster.release.environment_version,
|
new_cluster.release.environment_version,
|
||||||
vips
|
(new_vips, id_name_vips_mapping),
|
||||||
)
|
)
|
||||||
new_net_manager.assign_given_vips_for_net_groups(vips)
|
new_net_manager.assign_given_vips_for_net_groups(new_vips)
|
||||||
new_net_manager.assign_vips_for_net_groups()
|
new_net_manager.assign_vips_for_net_groups()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def reassociate_vips(cls, vips, netgroups_id_mapping):
|
||||||
|
new_vips = collections.defaultdict(dict)
|
||||||
|
for orig_net_id, net_vips in vips.items():
|
||||||
|
new_net_id = netgroups_id_mapping[orig_net_id]
|
||||||
|
new_vips[new_net_id] = net_vips
|
||||||
|
return new_vips
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_id_name_vips_mapping(self, vips):
|
||||||
|
mapping = {}
|
||||||
|
for vip_id in vips:
|
||||||
|
mapping[vip_id] = \
|
||||||
|
adapters.NailgunNetworkGroupAdapter.get_by_uid(vip_id).name
|
||||||
|
return mapping
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_node_roles(cls, reprovision, current_roles, given_roles):
|
def get_node_roles(cls, reprovision, current_roles, given_roles):
|
||||||
"""Return roles depending on the reprovisioning status.
|
"""Return roles depending on the reprovisioning status.
|
||||||
|
@ -210,8 +252,10 @@ class UpgradeHelper(object):
|
||||||
orig_ng = orig_cluster.get_network_groups()
|
orig_ng = orig_cluster.get_network_groups()
|
||||||
seed_ng = seed_cluster.get_network_groups()
|
seed_ng = seed_cluster.get_network_groups()
|
||||||
|
|
||||||
seed_ng_dict = dict((ng.name, ng.id) for ng in seed_ng)
|
seed_ng_dict = dict(((ng.name, ng.nodegroup.name), ng.id)
|
||||||
mapping = dict((ng.id, seed_ng_dict[ng.name]) for ng in orig_ng)
|
for ng in seed_ng)
|
||||||
|
mapping = dict((ng.id, seed_ng_dict[(ng.name, ng.nodegroup.name)])
|
||||||
|
for ng in orig_ng)
|
||||||
mapping[orig_cluster.get_admin_network_group().id] = \
|
mapping[orig_cluster.get_admin_network_group().id] = \
|
||||||
seed_cluster.get_admin_network_group().id
|
seed_cluster.get_admin_network_group().id
|
||||||
return mapping
|
return mapping
|
||||||
|
|
Loading…
Reference in New Issue