390 lines
16 KiB
Python
390 lines
16 KiB
Python
#
|
|
# Copyright (c) 2023 Wind River Systems, Inc.
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
|
|
import json
|
|
import mock
|
|
import uuid
|
|
|
|
from dccommon import exceptions as dccommon_exceptions
|
|
from dcmanager.db.sqlalchemy import api as db_api
|
|
from dcmanager.manager import system_peer_manager
|
|
from dcmanager.tests import base
|
|
from dcmanager.tests.unit.common import fake_subcloud
|
|
|
|
# FAKE SYSINV DATA
|
|
FAKE_SITE0_SYSTEM_UUID = str(uuid.uuid4())
|
|
FAKE_SITE1_SYSTEM_UUID = str(uuid.uuid4())
|
|
|
|
# FAKE SYSTEM PEER DATA
|
|
FAKE_SYSTEM_PEER_ID = 1
|
|
FAKE_SYSTEM_PEER_UUID = FAKE_SITE1_SYSTEM_UUID
|
|
FAKE_SYSTEM_PEER_NAME = 'PeerSite1'
|
|
FAKE_MANAGER_ENDPOINT = 'http://128.128.128.128:5000/v3'
|
|
FAKE_MANAGER_USERNAME = 'admin'
|
|
FAKE_MANAGER_PASSWORD = 'cGFzc3dvcmQ='
|
|
FAKE_PEER_CONTROLLER_GATEWAY_IP = '128.128.1.1'
|
|
|
|
# FAKE SUBCLOUD PEER GROUP DATA (SITE0)
|
|
FAKE_SITE0_PEER_GROUP_ID = 1
|
|
FAKE_SITE0_PEER_GROUP_NAME = 'PeerGroup1'
|
|
FAKE_SITE0_PEER_GROUP_SYSTEM_LEADER_ID = FAKE_SITE0_SYSTEM_UUID
|
|
FAKE_SITE0_PEER_GROUP_SYSTEM_LEADER_NAME = 'site0'
|
|
FAKE_SITE0_PEER_GROUP_MAX_SUBCLOUDS_REHOMING = 50
|
|
FAKE_SITE0_PEER_GROUP_PRIORITY = 0
|
|
FAKE_SITE0_PEER_GROUP_STATE = 'enabled'
|
|
|
|
# FAKE SUBCLOUD PEER GROUP DATA (SITE1)
|
|
FAKE_SITE1_PEER_GROUP_ID = 9
|
|
|
|
# FAKE SUBCLOUD DATA (SITE1)
|
|
FAKE_SITE1_SUBCLOUD1_ID = 11
|
|
FAKE_SITE1_SUBCLOUD1_DEPLOY_STATUS = 'secondary'
|
|
FAKE_SITE1_SUBCLOUD1_DATA = {"id": FAKE_SITE1_SUBCLOUD1_ID,
|
|
"name": "subcloud1",
|
|
"region-name": "subcloud1",
|
|
"deploy-status":
|
|
FAKE_SITE1_SUBCLOUD1_DEPLOY_STATUS}
|
|
FAKE_SITE1_SUBCLOUD2_ID = 12
|
|
FAKE_SITE1_SUBCLOUD2_DEPLOY_STATUS = 'secondary-failed'
|
|
FAKE_SITE1_SUBCLOUD2_DATA = {"id": FAKE_SITE1_SUBCLOUD2_ID,
|
|
"name": "subcloud2",
|
|
"region-name": "subcloud2",
|
|
"deploy-status":
|
|
FAKE_SITE1_SUBCLOUD2_DEPLOY_STATUS}
|
|
FAKE_SITE1_SUBCLOUD3_ID = 13
|
|
FAKE_SITE1_SUBCLOUD3_DEPLOY_STATUS = 'secondary'
|
|
FAKE_SITE1_SUBCLOUD3_DATA = {"id": FAKE_SITE1_SUBCLOUD3_ID,
|
|
"name": "subcloud3",
|
|
"region-name": "subcloud3",
|
|
"deploy-status":
|
|
FAKE_SITE1_SUBCLOUD3_DEPLOY_STATUS}
|
|
|
|
# FAKE PEER GROUP ASSOCIATION DATA
|
|
FAKE_ASSOCIATION_PEER_GROUP_ID = \
|
|
FAKE_SITE0_PEER_GROUP_ID
|
|
FAKE_ASSOCIATION_SYSTEM_PEER_ID = \
|
|
FAKE_SYSTEM_PEER_ID
|
|
FAKE_ASSOCIATION_PEER_GROUP_PRIORITY = 1
|
|
FAKE_ASSOCIATION_SYNC_STATUS = 'synced'
|
|
FAKE_ASSOCIATION_SYNC_MESSAGE = 'None'
|
|
|
|
|
|
class FakeDCManagerAuditAPI(object):
|
|
def __init__(self):
|
|
pass
|
|
|
|
|
|
class FakeSystem(object):
|
|
def __init__(self, uuid):
|
|
self.uuid = uuid
|
|
|
|
|
|
class FakePeerGroup(object):
|
|
def __init__(self):
|
|
self.id = FAKE_SITE1_PEER_GROUP_ID
|
|
|
|
|
|
class FakeKeystoneClient(object):
|
|
def __init__(self):
|
|
self.keystone_client = mock.MagicMock()
|
|
self.session = mock.MagicMock()
|
|
self.endpoint_cache = mock.MagicMock()
|
|
|
|
|
|
class FakeSysinvClient(object):
|
|
def __init__(self):
|
|
self.system = FakeSystem(FAKE_SITE1_SYSTEM_UUID)
|
|
|
|
def get_system(self):
|
|
return self.system
|
|
|
|
|
|
class FakeDcmanagerClient(object):
|
|
def __init__(self):
|
|
self.peer_groups = [FakePeerGroup()]
|
|
|
|
def add_subcloud_peer_group(self, **kwargs):
|
|
return self.peer_groups
|
|
|
|
def get_subcloud_peer_group(self, peer_group_name):
|
|
return self.peer_groups
|
|
|
|
|
|
class FakeException(Exception):
|
|
pass
|
|
|
|
|
|
class TestSystemPeerManager(base.DCManagerTestCase):
|
|
def setUp(self):
|
|
super(TestSystemPeerManager, self).setUp()
|
|
|
|
# Mock the DCManager Audit API
|
|
self.fake_dcmanager_audit_api = FakeDCManagerAuditAPI()
|
|
p = mock.patch('dcmanager.audit.rpcapi.ManagerAuditClient')
|
|
self.mock_dcmanager_audit_api = p.start()
|
|
self.mock_dcmanager_audit_api.return_value = \
|
|
self.fake_dcmanager_audit_api
|
|
self.addCleanup(p.stop)
|
|
|
|
@staticmethod
|
|
def create_subcloud_with_pg_static(ctxt, peer_group_id,
|
|
rehome_data=None, **kwargs):
|
|
subcloud = fake_subcloud.create_fake_subcloud(ctxt, **kwargs)
|
|
return db_api.subcloud_update(ctxt, subcloud.id,
|
|
peer_group_id=peer_group_id,
|
|
rehome_data=rehome_data)
|
|
|
|
@staticmethod
|
|
def create_system_peer_static(ctxt, **kwargs):
|
|
values = {
|
|
'peer_uuid': FAKE_SYSTEM_PEER_UUID,
|
|
'peer_name': FAKE_SYSTEM_PEER_NAME,
|
|
'endpoint': FAKE_MANAGER_ENDPOINT,
|
|
'username': FAKE_MANAGER_USERNAME,
|
|
'password': FAKE_MANAGER_PASSWORD,
|
|
'gateway_ip': FAKE_PEER_CONTROLLER_GATEWAY_IP
|
|
}
|
|
values.update(kwargs)
|
|
return db_api.system_peer_create(ctxt, **values)
|
|
|
|
@staticmethod
|
|
def create_subcloud_peer_group_static(ctxt, **kwargs):
|
|
values = {
|
|
"peer_group_name": FAKE_SITE0_PEER_GROUP_NAME,
|
|
"system_leader_id": FAKE_SITE0_PEER_GROUP_SYSTEM_LEADER_ID,
|
|
"system_leader_name": FAKE_SITE0_PEER_GROUP_SYSTEM_LEADER_NAME,
|
|
"group_priority": FAKE_SITE0_PEER_GROUP_PRIORITY,
|
|
"group_state": FAKE_SITE0_PEER_GROUP_STATE,
|
|
"max_subcloud_rehoming":
|
|
FAKE_SITE0_PEER_GROUP_MAX_SUBCLOUDS_REHOMING
|
|
}
|
|
values.update(kwargs)
|
|
return db_api.subcloud_peer_group_create(ctxt, **values)
|
|
|
|
@staticmethod
|
|
def create_peer_group_association_static(ctxt, **kwargs):
|
|
values = {
|
|
"system_peer_id": FAKE_ASSOCIATION_SYSTEM_PEER_ID,
|
|
"peer_group_id": FAKE_ASSOCIATION_PEER_GROUP_ID,
|
|
"peer_group_priority": FAKE_ASSOCIATION_PEER_GROUP_PRIORITY,
|
|
"sync_status": FAKE_ASSOCIATION_SYNC_STATUS,
|
|
"sync_message": FAKE_ASSOCIATION_SYNC_MESSAGE
|
|
}
|
|
values.update(kwargs)
|
|
return db_api.peer_group_association_create(ctxt, **values)
|
|
|
|
def test_init(self):
|
|
spm = system_peer_manager.SystemPeerManager()
|
|
self.assertIsNotNone(spm)
|
|
self.assertEqual('system_peer_manager', spm.service_name)
|
|
self.assertEqual('localhost', spm.host)
|
|
|
|
@mock.patch.object(system_peer_manager, 'PeerSiteDriver')
|
|
@mock.patch.object(system_peer_manager, 'SysinvClient')
|
|
@mock.patch.object(system_peer_manager, 'DcmanagerClient')
|
|
def test_sync_subclouds(self, mock_dc_client,
|
|
mock_sysinv_client,
|
|
mock_keystone_client):
|
|
mock_keystone_client().keystone_client = FakeKeystoneClient()
|
|
mock_sysinv_client.return_value = FakeSysinvClient()
|
|
mock_dc_client.return_value = FakeDcmanagerClient()
|
|
mock_dc_client().add_subcloud_with_secondary_status = mock.MagicMock()
|
|
mock_dc_client().delete_subcloud = mock.MagicMock()
|
|
|
|
peer = self.create_system_peer_static(
|
|
self.ctx,
|
|
peer_name='SystemPeer1')
|
|
peer_group = self.create_subcloud_peer_group_static(
|
|
self.ctx,
|
|
peer_group_name='SubcloudPeerGroup1')
|
|
rehome_data = {
|
|
"saved_payload": {
|
|
"bootstrap-address": "192.168.10.10",
|
|
"systemcontroller_gateway_address": "192.168.204.101"
|
|
}
|
|
}
|
|
# Create local dc subcloud1 mock data in database
|
|
self.create_subcloud_with_pg_static(
|
|
self.ctx,
|
|
peer_group_id=peer_group.id,
|
|
rehome_data=json.dumps(rehome_data),
|
|
name='subcloud1',
|
|
region_name='subcloud1')
|
|
# Create local dc subcloud2 mock data in database
|
|
self.create_subcloud_with_pg_static(
|
|
self.ctx,
|
|
peer_group_id=peer_group.id,
|
|
rehome_data=json.dumps(rehome_data),
|
|
name='subcloud2',
|
|
region_name='subcloud2')
|
|
peer_subcloud1 = FAKE_SITE1_SUBCLOUD1_DATA
|
|
peer_subcloud2 = FAKE_SITE1_SUBCLOUD2_DATA
|
|
peer_subcloud3 = FAKE_SITE1_SUBCLOUD3_DATA
|
|
mock_dc_client().get_subcloud = mock.MagicMock()
|
|
mock_dc_client().get_subcloud.side_effect = [
|
|
peer_subcloud1, dccommon_exceptions.SubcloudNotFound,
|
|
peer_subcloud1, dccommon_exceptions.SubcloudNotFound,
|
|
peer_subcloud3]
|
|
mock_dc_client().get_subcloud_list_by_peer_group = mock.MagicMock()
|
|
mock_dc_client().get_subcloud_list_by_peer_group.return_value = [
|
|
peer_subcloud1, peer_subcloud2, peer_subcloud3]
|
|
mock_dc_client().update_subcloud = mock.MagicMock()
|
|
mock_dc_client().update_subcloud.side_effect = [
|
|
peer_subcloud1, peer_subcloud1, peer_subcloud2]
|
|
|
|
spm = system_peer_manager.SystemPeerManager()
|
|
spm._sync_subclouds(self.ctx, peer, peer_group.id,
|
|
FAKE_SITE1_PEER_GROUP_ID)
|
|
|
|
mock_dc_client().get_subcloud.assert_has_calls([
|
|
mock.call(peer_subcloud1.get('name')),
|
|
mock.call(peer_subcloud2.get('name')),
|
|
mock.call(peer_subcloud3.get('name'))
|
|
])
|
|
mock_dc_client().update_subcloud.assert_has_calls([
|
|
mock.call('subcloud1', mock.ANY, mock.ANY),
|
|
mock.call('subcloud1', files=None,
|
|
data={'peer_group': str(FAKE_SITE1_PEER_GROUP_ID)})
|
|
])
|
|
mock_dc_client().add_subcloud_with_secondary_status. \
|
|
assert_called_once()
|
|
mock_dc_client().delete_subcloud.assert_called_once_with('subcloud3')
|
|
|
|
@mock.patch.object(
|
|
system_peer_manager.SystemPeerManager, '_sync_subclouds')
|
|
@mock.patch.object(system_peer_manager, 'PeerSiteDriver')
|
|
@mock.patch.object(system_peer_manager, 'SysinvClient')
|
|
@mock.patch.object(system_peer_manager, 'DcmanagerClient')
|
|
def test_sync_subcloud_peer_group(self,
|
|
mock_dc_client,
|
|
mock_sysinv_client,
|
|
mock_keystone_client,
|
|
mock_sync_subclouds):
|
|
mock_sync_subclouds.return_value = True
|
|
mock_keystone_client().keystone_client = FakeKeystoneClient()
|
|
mock_sysinv_client.return_value = FakeSysinvClient()
|
|
mock_dc_client.return_value = FakeDcmanagerClient()
|
|
mock_dc_client().get_subcloud_peer_group = mock.MagicMock()
|
|
mock_dc_client().update_subcloud_peer_group = mock.MagicMock()
|
|
|
|
peer = self.create_system_peer_static(
|
|
self.ctx,
|
|
peer_name='SystemPeer1')
|
|
peer_group = self.create_subcloud_peer_group_static(
|
|
self.ctx,
|
|
peer_group_name='SubcloudPeerGroup1')
|
|
association = self.create_peer_group_association_static(
|
|
self.ctx,
|
|
system_peer_id=peer.id,
|
|
peer_group_id=peer_group.id)
|
|
|
|
spm = system_peer_manager.SystemPeerManager()
|
|
spm.sync_subcloud_peer_group(self.ctx, association.id, False)
|
|
|
|
mock_dc_client().get_subcloud_peer_group.assert_called_once_with(
|
|
peer_group.peer_group_name)
|
|
mock_dc_client().update_subcloud_peer_group.assert_called_once()
|
|
|
|
@mock.patch.object(
|
|
system_peer_manager.SystemPeerManager, '_sync_subclouds')
|
|
@mock.patch.object(system_peer_manager, 'PeerSiteDriver')
|
|
@mock.patch.object(system_peer_manager, 'SysinvClient')
|
|
@mock.patch.object(system_peer_manager, 'DcmanagerClient')
|
|
def test_sync_subcloud_peer_group_not_exist(self, mock_dc_client,
|
|
mock_sysinv_client,
|
|
mock_keystone_client,
|
|
mock_sync_subclouds):
|
|
mock_sync_subclouds.return_value = True
|
|
mock_keystone_client().keystone_client = FakeKeystoneClient()
|
|
mock_sysinv_client.return_value = FakeSysinvClient()
|
|
mock_dc_client.return_value = FakeDcmanagerClient()
|
|
mock_dc_client().get_subcloud_peer_group = mock.MagicMock()
|
|
mock_dc_client().add_subcloud_peer_group = mock.MagicMock()
|
|
mock_dc_client().update_subcloud_peer_group = mock.MagicMock()
|
|
|
|
peer = self.create_system_peer_static(
|
|
self.ctx,
|
|
peer_name='SystemPeer1')
|
|
peer_group = self.create_subcloud_peer_group_static(
|
|
self.ctx,
|
|
peer_group_name='SubcloudPeerGroup1')
|
|
association = self.create_peer_group_association_static(
|
|
self.ctx,
|
|
system_peer_id=peer.id,
|
|
peer_group_id=peer_group.id)
|
|
|
|
mock_dc_client().get_subcloud_peer_group.side_effect = \
|
|
dccommon_exceptions.SubcloudPeerGroupNotFound
|
|
|
|
spm = system_peer_manager.SystemPeerManager()
|
|
spm.sync_subcloud_peer_group(self.ctx, association.id, False)
|
|
|
|
mock_dc_client().get_subcloud_peer_group.assert_called_once_with(
|
|
peer_group.peer_group_name)
|
|
mock_dc_client().add_subcloud_peer_group.assert_called_once_with(**{
|
|
'peer-group-name': peer_group.peer_group_name,
|
|
'group-priority': association.peer_group_priority,
|
|
'group-state': peer_group.group_state,
|
|
'system-leader-id': peer_group.system_leader_id,
|
|
'system-leader-name': peer_group.system_leader_name,
|
|
'max-subcloud-rehoming': peer_group.max_subcloud_rehoming
|
|
})
|
|
mock_dc_client().update_subcloud_peer_group.assert_not_called()
|
|
|
|
@mock.patch.object(system_peer_manager, 'PeerSiteDriver')
|
|
@mock.patch.object(system_peer_manager, 'DcmanagerClient')
|
|
def test_delete_peer_group_association(self,
|
|
mock_dc_client,
|
|
mock_keystone_client):
|
|
mock_keystone_client().keystone_client = FakeKeystoneClient()
|
|
mock_dc_client.return_value = FakeDcmanagerClient()
|
|
mock_dc_client().delete_subcloud_peer_group = mock.MagicMock()
|
|
mock_dc_client().delete_subcloud = mock.MagicMock()
|
|
|
|
peer = self.create_system_peer_static(
|
|
self.ctx,
|
|
peer_name='SystemPeer1')
|
|
peer_group = self.create_subcloud_peer_group_static(
|
|
self.ctx,
|
|
peer_group_name='SubcloudPeerGroup1')
|
|
# Create local dc subcloud1 mock data in database
|
|
subcloud1 = self.create_subcloud_with_pg_static(
|
|
self.ctx,
|
|
peer_group_id=peer_group.id,
|
|
name='subcloud1')
|
|
# Create local dc subcloud2 mock data in database
|
|
subcloud2 = self.create_subcloud_with_pg_static(
|
|
self.ctx,
|
|
peer_group_id=peer_group.id,
|
|
name='subcloud2')
|
|
association = self.create_peer_group_association_static(
|
|
self.ctx,
|
|
system_peer_id=peer.id,
|
|
peer_group_id=peer_group.id)
|
|
peer_subcloud1 = FAKE_SITE1_SUBCLOUD1_DATA
|
|
peer_subcloud2 = FAKE_SITE1_SUBCLOUD2_DATA
|
|
mock_dc_client().get_subcloud = mock.MagicMock()
|
|
mock_dc_client().get_subcloud.side_effect = [
|
|
peer_subcloud1, peer_subcloud2]
|
|
|
|
mock_dc_client().get_subcloud_peer_group = mock.MagicMock()
|
|
mock_dc_client().get_subcloud_peer_group.return_value = {
|
|
'group_priority': 1
|
|
}
|
|
|
|
spm = system_peer_manager.SystemPeerManager()
|
|
spm.delete_peer_group_association(self.ctx, association.id)
|
|
|
|
mock_dc_client().delete_subcloud.assert_has_calls([
|
|
mock.call(subcloud1.name),
|
|
mock.call(subcloud2.name)
|
|
])
|
|
mock_dc_client().delete_subcloud_peer_group.assert_called_once_with(
|
|
peer_group.peer_group_name)
|
|
|
|
associations = db_api.peer_group_association_get_all(self.ctx)
|
|
self.assertEqual(0, len(associations))
|