Restrict subcloud deploy configure to primary site

Restrict subcloud's secondary sites (the peer site where
subcloud in SPG can be migrated to) from reconfiguring
the subcloud. This is necessary because subcloud reconfig
may update the OpenStack endpoints/routes/network IPs and impact
the ability to migrate the subcloud back to the primary site.

- Introduced a check in "deploy configure" to ensure that
the target subcloud is managed by its primary site. The site
status is inferred from the subcloud's peer group priority on the site.

Test Plan:
Setup a DC system with GR configuration (2 sites + subclouds) and
verify the  "subcloud deploy config" command with the following arrangements:
1. PASS: For a subcloud that's not part of protection group
         (not in any SPG / not part of GR),
         ensure that the operation is not restricted.
2. PASS: Add subcloud to SPG and keep it managed by primary site,
         ensure that the operation is not restricted.
3. PASS: Add system peer, create SPG association with a secondary
         site, and migrate the subcloud from #2. Verify that "deploy
         config" is restricted and it fails with following error
         message: "Subcloud must be managed by its primary site"
4. PASS: Using the subcloud from #3, migrate it back to the primary
         site. Attempt to deploy config and ensure that the operation
         is not restricted.

Closes-Bug: 2054161

Change-Id: I7e986771a32882bfad917c85439e6f6b99dfe173
Signed-off-by: Salman Rana <salman.rana@windriver.com>
This commit is contained in:
Salman Rana 2024-02-16 15:00:25 -05:00
parent 23e2cf4a85
commit fc0a5f0e53
4 changed files with 60 additions and 4 deletions

View File

@ -31,7 +31,6 @@ from dcmanager.rpc import client as rpc_client
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
PEER_GROUP_PRIMARY_PRIORITY = 0
MIN_PEER_GROUP_ASSOCIATION_PRIORITY = 1
MAX_PEER_GROUP_ASSOCIATION_PRIORITY = 65536
ASSOCIATION_SYNC_STATUS_LIST = \
@ -191,9 +190,9 @@ class PeerGroupAssociationsController(restcomm.GenericPathController):
pecan.abort(httpclient.BAD_REQUEST,
_('Invalid peer_group_priority'))
if (peer_group.group_priority == PEER_GROUP_PRIMARY_PRIORITY and
if (peer_group.group_priority == consts.PEER_GROUP_PRIMARY_PRIORITY and
peer_group_priority is None) or (
peer_group.group_priority > PEER_GROUP_PRIMARY_PRIORITY and
peer_group.group_priority > consts.PEER_GROUP_PRIMARY_PRIORITY and
peer_group_priority is not None):
pecan.abort(httpclient.BAD_REQUEST,
_('Peer Group Association create is not allowed when '
@ -201,7 +200,7 @@ class PeerGroupAssociationsController(restcomm.GenericPathController):
'and it is required when the subcloud peer group '
'priority is 0.'))
is_primary = peer_group.group_priority == PEER_GROUP_PRIMARY_PRIORITY
is_primary = peer_group.group_priority == consts.PEER_GROUP_PRIMARY_PRIORITY
# only one combination of peer_group_id + system_peer_id can exists
association = None

View File

@ -309,6 +309,17 @@ class PhasedSubcloudDeployController(object):
pecan.abort(400, _('Subcloud prestage is ongoing %s') %
subcloud.prestage_status)
# If the subcloud belongs to a peer group, ensure that
# it's not being configured in a secondary site.
if subcloud.peer_group_id is not None:
peer_group = utils.subcloud_peer_group_get_by_ref(
context, str(subcloud.peer_group_id))
if peer_group is not None:
if peer_group.group_priority != consts.PEER_GROUP_PRIMARY_PRIORITY:
pecan.abort(400,
_('Subcloud can only be configured in'
' its primary site.'))
psd_common.populate_payload_with_pre_existing_data(
payload, subcloud, SUBCLOUD_CONFIG_GET_FILE_CONTENTS)

View File

@ -461,6 +461,8 @@ PEER_GROUP_MIGRATING = 'migrating'
PEER_GROUP_MIGRATION_COMPLETE = 'complete'
PEER_GROUP_MIGRATION_NONE = 'none'
PEER_GROUP_PRIMARY_PRIORITY = 0
# Peer group association type
ASSOCIATION_TYPE_PRIMARY = 'primary'
ASSOCIATION_TYPE_NON_PRIMARY = 'non-primary'

View File

@ -28,6 +28,8 @@ from dcmanager.tests.unit.api.v1.controllers.test_subclouds import \
from dcmanager.tests.unit.api.v1.controllers.test_subclouds import \
TestSubcloudPost
from dcmanager.tests.unit.common import fake_subcloud
from dcmanager.tests.unit.manager.test_system_peer_manager import \
TestSystemPeerManager
from dcmanager.tests import utils
FAKE_URL = '/v1.0/phased-subcloud-deploy'
@ -345,6 +347,48 @@ class TestSubcloudDeployConfig(testroot.DCManagerApiTest):
str(subcloud.id) + '/configure',
headers=FAKE_HEADERS, params=data)
def test_configure_primary_subcloud_peer_group(self):
data_install = copy.copy(FAKE_SUBCLOUD_INSTALL_VALUES)
data_install.pop('software_version')
fake_password = \
(base64.b64encode('testpass'.encode("utf-8"))).decode('ascii')
data = {'sysadmin_password': fake_password}
self.mock_rpc_client().subcloud_deploy_config.return_value = True
self.mock_get_request_data.return_value = data
# Create a subcloud and add it to SPG with primary priority
peer_group = TestSystemPeerManager.create_subcloud_peer_group_static(
self.ctx,
group_priority=consts.PEER_GROUP_PRIMARY_PRIORITY,
peer_group_name='SubcloudPeerGroup1')
subcloud = TestSystemPeerManager.create_subcloud_with_pg_static(
self.ctx,
peer_group_id=peer_group.id,
name='subcloud1',
data_install=json.dumps(data_install))
response = self.app.patch_json(FAKE_URL + '/' + str(subcloud.id) +
'/configure',
headers=FAKE_HEADERS,
params=data)
self.mock_rpc_client().subcloud_deploy_config.assert_called_once_with(
mock.ANY, subcloud.id, data, initial_deployment=True)
self.assertEqual(response.status_int, 200)
# Change the SPG as if it was on peer site
db_api.subcloud_peer_group_update(
self.ctx,
peer_group.id,
group_priority=consts.PEER_GROUP_PRIMARY_PRIORITY + 1)
six.assertRaisesRegex(self, webtest.app.AppError, "400 *",
self.app.patch_json, FAKE_URL + '/' +
str(subcloud.id) + '/configure',
headers=FAKE_HEADERS, params=data)
class TestSubcloudDeployInstall(testroot.DCManagerApiTest):
def setUp(self):