Show Subcloud Deploy Configuration Status
This commit extends the "dcmanager subcloud show <subcloud> --detail" command to display the deploy configuration status of the subcloud from the systemcontroller. The presence of a 260.002 alarm related to a 'host' resource on an online subcloud indicates an outdated deploy configuration. In such cases, the field will display "Deployment: configurations out-of-date". Otherwise, the field will show: "Deployment: configurations up-to-date". The field will not be shown for offline subclouds. Test Plan: PASS: Successful bring up of a fresh DC system with these changes. PASS: Run 'dcmanager subcloud show' without the '--detail' argument. Verify that the new field is not being shown. PASS: Run 'dcmanager subcloud show --detail' for an online subcloud containing a 260.002 alarm related to a host resource. Verify that the output contains 'Deployment: configurations out-of-date'. PASS: Run 'dcmanager subcloud show --detail' for an online subcloud containing a 260.002 alarm related to a resource other than host. Verify that the output contains 'Deployment: configurations up-to-date'. PASS: Run 'dcmanager subcloud show --detail' for an online subcloud without a 260.002 alarm. Verify that the output contains 'Deployment: configurations up-to-date'. PASS: Run 'dcmanager subcloud show --detail' for an offline subcloud. Verify that the new field is not being shown. Story: 2010719 Task: 48025 Change-Id: I223919ded1d6d5dfcc81c2060c5e6491ed8a73d9 Signed-off-by: Enzo Candotti <enzo.candotti@windriver.com>
This commit is contained in:
parent
f174505b66
commit
e88471cd38
@ -21,6 +21,7 @@
|
|||||||
"data_install": null,
|
"data_install": null,
|
||||||
"data_upgrade": null,
|
"data_upgrade": null,
|
||||||
"oam_floating_ip": "192.168.101.2",
|
"oam_floating_ip": "192.168.101.2",
|
||||||
|
"config_sync_status": "Deployment: configurations up-to-date"
|
||||||
"endpoint_sync_status": [
|
"endpoint_sync_status": [
|
||||||
{
|
{
|
||||||
"sync_status": "in-sync",
|
"sync_status": "in-sync",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2020-2022 Wind River Systems, Inc.
|
# Copyright (c) 2020-2023 Wind River Systems, Inc.
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
# not use this file except in compliance with the License. You may obtain
|
# not use this file except in compliance with the License. You may obtain
|
||||||
# a copy of the License at
|
# a copy of the License at
|
||||||
@ -124,6 +124,11 @@ SYNC_STATUS_UNKNOWN = "unknown"
|
|||||||
SYNC_STATUS_IN_SYNC = "in-sync"
|
SYNC_STATUS_IN_SYNC = "in-sync"
|
||||||
SYNC_STATUS_OUT_OF_SYNC = "out-of-sync"
|
SYNC_STATUS_OUT_OF_SYNC = "out-of-sync"
|
||||||
|
|
||||||
|
# Subcloud deploy configuration status
|
||||||
|
DEPLOY_CONFIG_UP_TO_DATE = 'Deployment: configurations up-to-date'
|
||||||
|
DEPLOY_CONFIG_OUT_OF_DATE = 'Deployment: configurations out-of-date'
|
||||||
|
MONITORED_ALARM_ENTITIES = ['host.starlingx.windriver.com', ]
|
||||||
|
|
||||||
# OS type
|
# OS type
|
||||||
OS_RELEASE_FILE = '/etc/os-release'
|
OS_RELEASE_FILE = '/etc/os-release'
|
||||||
OS_CENTOS = 'centos'
|
OS_CENTOS = 'centos'
|
||||||
|
@ -39,6 +39,7 @@ from pecan import expose
|
|||||||
from pecan import request
|
from pecan import request
|
||||||
|
|
||||||
from dccommon import consts as dccommon_consts
|
from dccommon import consts as dccommon_consts
|
||||||
|
from dccommon.drivers.openstack.fm import FmClient
|
||||||
from dccommon.drivers.openstack import patching_v1
|
from dccommon.drivers.openstack import patching_v1
|
||||||
from dccommon.drivers.openstack.patching_v1 import PatchingClient
|
from dccommon.drivers.openstack.patching_v1 import PatchingClient
|
||||||
from dccommon.drivers.openstack.sdk_platform import OpenStackDriver
|
from dccommon.drivers.openstack.sdk_platform import OpenStackDriver
|
||||||
@ -61,6 +62,7 @@ from dcmanager.common import utils
|
|||||||
from dcmanager.db import api as db_api
|
from dcmanager.db import api as db_api
|
||||||
|
|
||||||
from dcmanager.rpc import client as rpc_client
|
from dcmanager.rpc import client as rpc_client
|
||||||
|
from fm_api.constants import FM_ALARM_ID_UNSYNCHRONIZED_RESOURCE
|
||||||
from six.moves import range
|
from six.moves import range
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
@ -1006,12 +1008,11 @@ class SubcloudsController(object):
|
|||||||
return sysinv_client.get_management_address_pool()
|
return sysinv_client.get_management_address_pool()
|
||||||
|
|
||||||
# TODO(gsilvatr): refactor to use implementation from common/utils and test
|
# TODO(gsilvatr): refactor to use implementation from common/utils and test
|
||||||
def _get_oam_addresses(self, context, subcloud_name):
|
def _get_oam_addresses(self, context, subcloud_name, sc_ks_client):
|
||||||
"""Get the subclouds oam addresses"""
|
"""Get the subclouds oam addresses"""
|
||||||
|
|
||||||
# First need to retrieve the Subcloud's Keystone session
|
# First need to retrieve the Subcloud's Keystone session
|
||||||
try:
|
try:
|
||||||
sc_ks_client = self.get_ks_client(subcloud_name)
|
|
||||||
endpoint = sc_ks_client.endpoint_cache.get_endpoint('sysinv')
|
endpoint = sc_ks_client.endpoint_cache.get_endpoint('sysinv')
|
||||||
sysinv_client = SysinvClient(subcloud_name,
|
sysinv_client = SysinvClient(subcloud_name,
|
||||||
sc_ks_client.session,
|
sc_ks_client.session,
|
||||||
@ -1027,6 +1028,31 @@ class SubcloudsController(object):
|
|||||||
LOG.error(message)
|
LOG.error(message)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _get_deploy_config_sync_status(self, context, subcloud_name, keystone_client):
|
||||||
|
"""Get the deploy configuration insync status of the subcloud """
|
||||||
|
detected_alarms = None
|
||||||
|
try:
|
||||||
|
fm_client = FmClient(subcloud_name, keystone_client.session)
|
||||||
|
detected_alarms = fm_client.get_alarms_by_id(
|
||||||
|
FM_ALARM_ID_UNSYNCHRONIZED_RESOURCE)
|
||||||
|
except Exception as ex:
|
||||||
|
LOG.error(str(ex))
|
||||||
|
return None
|
||||||
|
|
||||||
|
out_of_date = False
|
||||||
|
if detected_alarms:
|
||||||
|
# Check if any alarm.entity_instance_id contains any of the values
|
||||||
|
# in MONITORED_ALARM_ENTITIES.
|
||||||
|
# We want to scope 260.002 alarms to the host entity only.
|
||||||
|
out_of_date = any(
|
||||||
|
any(entity_id in alarm.entity_instance_id
|
||||||
|
for entity_id in dccommon_consts.MONITORED_ALARM_ENTITIES)
|
||||||
|
for alarm in detected_alarms
|
||||||
|
)
|
||||||
|
sync_status = dccommon_consts.DEPLOY_CONFIG_OUT_OF_DATE if out_of_date \
|
||||||
|
else dccommon_consts.DEPLOY_CONFIG_UP_TO_DATE
|
||||||
|
return sync_status
|
||||||
|
|
||||||
def _add_subcloud_to_database(self, context, payload):
|
def _add_subcloud_to_database(self, context, payload):
|
||||||
try:
|
try:
|
||||||
db_api.subcloud_get_by_name(context, payload['name'])
|
db_api.subcloud_get_by_name(context, payload['name'])
|
||||||
@ -1190,16 +1216,26 @@ class SubcloudsController(object):
|
|||||||
|
|
||||||
if detail is not None:
|
if detail is not None:
|
||||||
oam_floating_ip = "unavailable"
|
oam_floating_ip = "unavailable"
|
||||||
|
config_sync_status = "unknown"
|
||||||
if subcloud.availability_status == dccommon_consts.AVAILABILITY_ONLINE:
|
if subcloud.availability_status == dccommon_consts.AVAILABILITY_ONLINE:
|
||||||
|
|
||||||
|
# Get the keystone client that will be used
|
||||||
|
# for _get_deploy_config_sync_status and _get_oam_addresses
|
||||||
|
sc_ks_client = self.get_ks_client(subcloud.name)
|
||||||
oam_addresses = self._get_oam_addresses(context,
|
oam_addresses = self._get_oam_addresses(context,
|
||||||
subcloud.name)
|
subcloud.name, sc_ks_client)
|
||||||
if oam_addresses is not None:
|
if oam_addresses is not None:
|
||||||
oam_floating_ip = oam_addresses.oam_floating_ip
|
oam_floating_ip = oam_addresses.oam_floating_ip
|
||||||
|
|
||||||
floating_ip_dict = {"oam_floating_ip":
|
deploy_config_state = self._get_deploy_config_sync_status(
|
||||||
oam_floating_ip}
|
context, subcloud.name, sc_ks_client)
|
||||||
subcloud_dict.update(floating_ip_dict)
|
if deploy_config_state is not None:
|
||||||
|
config_sync_status = deploy_config_state
|
||||||
|
|
||||||
|
extra_details = {"oam_floating_ip": oam_floating_ip,
|
||||||
|
"config_sync_status": config_sync_status}
|
||||||
|
|
||||||
|
subcloud_dict.update(extra_details)
|
||||||
return subcloud_dict
|
return subcloud_dict
|
||||||
|
|
||||||
@utils.synchronized(LOCK_NAME)
|
@utils.synchronized(LOCK_NAME)
|
||||||
|
@ -1051,12 +1051,18 @@ class TestSubcloudAPIOther(testroot.DCManagerApiTest):
|
|||||||
self.assertEqual(response.json.get('oam_floating_ip', None), None)
|
self.assertEqual(response.json.get('oam_floating_ip', None), None)
|
||||||
self.assertEqual(response.json['name'], subcloud.name)
|
self.assertEqual(response.json['name'], subcloud.name)
|
||||||
|
|
||||||
|
@mock.patch.object(subclouds.SubcloudsController,
|
||||||
|
'_get_deploy_config_sync_status')
|
||||||
@mock.patch.object(subclouds.SubcloudsController,
|
@mock.patch.object(subclouds.SubcloudsController,
|
||||||
'_get_oam_addresses')
|
'_get_oam_addresses')
|
||||||
|
@mock.patch.object(subclouds.SubcloudsController,
|
||||||
|
'get_ks_client')
|
||||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||||
def test_get_online_subcloud_with_additional_detail(self,
|
def test_get_online_subcloud_with_additional_detail(self,
|
||||||
mock_rpc_client,
|
mock_rpc_client,
|
||||||
mock_get_oam_addresses):
|
mock_get_ks_client,
|
||||||
|
mock_get_oam_addresses,
|
||||||
|
mock_get_deploy_config_sync_status):
|
||||||
subcloud = fake_subcloud.create_fake_subcloud(self.ctx)
|
subcloud = fake_subcloud.create_fake_subcloud(self.ctx)
|
||||||
updated_subcloud = db_api.subcloud_update(
|
updated_subcloud = db_api.subcloud_update(
|
||||||
self.ctx, subcloud.id, availability_status=dccommon_consts.AVAILABILITY_ONLINE)
|
self.ctx, subcloud.id, availability_status=dccommon_consts.AVAILABILITY_ONLINE)
|
||||||
@ -1069,11 +1075,14 @@ class TestSubcloudAPIOther(testroot.DCManagerApiTest):
|
|||||||
'10.10.10.3',
|
'10.10.10.3',
|
||||||
'10.10.10.1',
|
'10.10.10.1',
|
||||||
'10.10.10.2')
|
'10.10.10.2')
|
||||||
|
mock_get_ks_client.return_value = 'ks_client'
|
||||||
mock_get_oam_addresses.return_value = oam_addresses
|
mock_get_oam_addresses.return_value = oam_addresses
|
||||||
|
mock_get_deploy_config_sync_status.return_value = dccommon_consts.DEPLOY_CONFIG_UP_TO_DATE
|
||||||
response = self.app.get(get_url, headers=FAKE_HEADERS)
|
response = self.app.get(get_url, headers=FAKE_HEADERS)
|
||||||
self.assertEqual(response.content_type, 'application/json')
|
self.assertEqual(response.content_type, 'application/json')
|
||||||
self.assertEqual(response.status_code, http_client.OK)
|
self.assertEqual(response.status_code, http_client.OK)
|
||||||
self.assertEqual('10.10.10.2', response.json['oam_floating_ip'])
|
self.assertEqual('10.10.10.2', response.json['oam_floating_ip'])
|
||||||
|
self.assertEqual('Deployment: configurations up-to-date', response.json['config_sync_status'])
|
||||||
|
|
||||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||||
def test_get_offline_subcloud_with_additional_detail(self,
|
def test_get_offline_subcloud_with_additional_detail(self,
|
||||||
@ -1084,18 +1093,47 @@ class TestSubcloudAPIOther(testroot.DCManagerApiTest):
|
|||||||
self.assertEqual(response.content_type, 'application/json')
|
self.assertEqual(response.content_type, 'application/json')
|
||||||
self.assertEqual(response.status_code, http_client.OK)
|
self.assertEqual(response.status_code, http_client.OK)
|
||||||
self.assertEqual('unavailable', response.json['oam_floating_ip'])
|
self.assertEqual('unavailable', response.json['oam_floating_ip'])
|
||||||
|
self.assertEqual('unknown', response.json['config_sync_status'])
|
||||||
|
|
||||||
|
@mock.patch.object(subclouds.SubcloudsController,
|
||||||
|
'_get_deploy_config_sync_status')
|
||||||
|
@mock.patch.object(subclouds.SubcloudsController,
|
||||||
|
'_get_oam_addresses')
|
||||||
|
@mock.patch.object(subclouds.SubcloudsController,
|
||||||
|
'get_ks_client')
|
||||||
|
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||||
|
def test_get_subcloud_deploy_config_status_unknown(self,
|
||||||
|
mock_rpc_client,
|
||||||
|
mock_get_ks_client,
|
||||||
|
mock_get_oam_addresses,
|
||||||
|
mock_get_deploy_config_sync_status):
|
||||||
|
subcloud = fake_subcloud.create_fake_subcloud(self.ctx)
|
||||||
|
updated_subcloud = db_api.subcloud_update(
|
||||||
|
self.ctx, subcloud.id, availability_status=dccommon_consts.AVAILABILITY_ONLINE)
|
||||||
|
get_url = FAKE_URL + '/' + str(updated_subcloud.id) + '/detail'
|
||||||
|
mock_get_ks_client.return_value = 'ks_client'
|
||||||
|
mock_get_oam_addresses.return_value = None
|
||||||
|
mock_get_deploy_config_sync_status.return_value = None
|
||||||
|
response = self.app.get(get_url, headers=FAKE_HEADERS)
|
||||||
|
self.assertEqual(response.content_type, 'application/json')
|
||||||
|
self.assertEqual(response.status_code, http_client.OK)
|
||||||
|
self.assertEqual('unknown', response.json['config_sync_status'])
|
||||||
|
|
||||||
@mock.patch.object(subclouds.SubcloudsController,
|
@mock.patch.object(subclouds.SubcloudsController,
|
||||||
'_get_oam_addresses')
|
'_get_oam_addresses')
|
||||||
|
@mock.patch.object(subclouds.SubcloudsController,
|
||||||
|
'get_ks_client')
|
||||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||||
def test_get_subcloud_oam_ip_unavailable(self,
|
def test_get_subcloud_oam_ip_unavailable(self,
|
||||||
mock_rpc_client,
|
mock_rpc_client,
|
||||||
|
mock_get_ks_client,
|
||||||
mock_get_oam_addresses):
|
mock_get_oam_addresses):
|
||||||
subcloud = fake_subcloud.create_fake_subcloud(self.ctx)
|
subcloud = fake_subcloud.create_fake_subcloud(self.ctx)
|
||||||
updated_subcloud = db_api.subcloud_update(
|
updated_subcloud = db_api.subcloud_update(
|
||||||
self.ctx, subcloud.id, availability_status=dccommon_consts.AVAILABILITY_ONLINE)
|
self.ctx, subcloud.id, availability_status=dccommon_consts.AVAILABILITY_ONLINE)
|
||||||
|
|
||||||
get_url = FAKE_URL + '/' + str(updated_subcloud.id) + '/detail'
|
get_url = FAKE_URL + '/' + str(updated_subcloud.id) + '/detail'
|
||||||
|
mock_get_ks_client.return_value = 'ks_client'
|
||||||
mock_get_oam_addresses.return_value = None
|
mock_get_oam_addresses.return_value = None
|
||||||
response = self.app.get(get_url, headers=FAKE_HEADERS)
|
response = self.app.get(get_url, headers=FAKE_HEADERS)
|
||||||
self.assertEqual(response.content_type, 'application/json')
|
self.assertEqual(response.content_type, 'application/json')
|
||||||
|
Loading…
Reference in New Issue
Block a user