Modify kube-rootca audit to alarm first
On previous installations, the subcloud kube-rootca certificate is different than the one from system controller. Currently, the audit is comparing cert_id and declaring out-of-sync if they don't match, which leads to an out-of-sync in the endpoint post upgrade. This commit changes the audit logic to first audit by alarms so upgraded subclouds can remain in-sync. Audit by cert_id still happen, but only if the subcloud was rehomed. Additionally, the force parameter was re-introduced in kube-rootca update orchestration. Since with alarm based audit different cert_ids can still present an in-sync status, the user might want to update subcloud cert to match system controller, so the force parameter is necessary to allow this. Note: Dcagent didn't previously allowed extra_args to be sent in in the payload. To avoid breaking audit with previous versions of dcagent sending an unknown key in the payload (which will thrown an error), extra_args are being sent in request header with the key "X-DCAGENT-HEADERS". Support for extra_args in the payload was added, but can only be used when all supported dcagent versions have this option. Note: Due to the current issue that blocks upgrade test, this commit did not test subcloud upgrade, but the scenario would follow a similar path from the second test case below, where updating a subcloud rootca to a different cert from system controller results in an in-sync endpoint status. Test plan: - PASS: Deploy a subcloud and verify kube-rootca_sync_status is in-sync. - PASS: Perform a kube-rootca update orchestration directly in the subcloud without passing a cert so it will auto generate one and verify kube-rootca_sync_status is still in-sync. - PASS: Rehome the subcloud from the previous test and verify kube-rootca_sync_status is out-of-sync. - PASS: Perform a kube-rootca update orchestration using dcmanager in an out-of-sync subcloud providing system controller certs and verify the final sync status is in-sync. - PASS: Perform a kube-rootca update orchestration using dcmanager in an in-sync subcloud with force parameter without providing certs and verify the final sync status is in-sync. - PASS: Install a N-1 release and verify kube-rootca_sync_status is in-sync. Closes-bug: 2092069 Change-Id: If0cc002d0d4970730771ae90d80dc50c7daf4d4c Signed-off-by: Victor Romano <victor.gluzromano@windriver.com>
This commit is contained in:
parent
ddb0c2451c
commit
e00c7223b5
@ -1257,6 +1257,7 @@ serviceUnavailable (503)
|
|||||||
- subcloud-apply-type: subcloud_apply_type
|
- subcloud-apply-type: subcloud_apply_type
|
||||||
- type: sw_update_strategy_type
|
- type: sw_update_strategy_type
|
||||||
- upload-only: patch_strategy_upload_only
|
- upload-only: patch_strategy_upload_only
|
||||||
|
- force: force_sync_status
|
||||||
|
|
||||||
Request Example
|
Request Example
|
||||||
----------------
|
----------------
|
||||||
|
@ -308,6 +308,13 @@ force:
|
|||||||
in: body
|
in: body
|
||||||
required: false
|
required: false
|
||||||
type: boolean
|
type: boolean
|
||||||
|
force_sync_status:
|
||||||
|
description: |
|
||||||
|
Indicates whether to disregard subcloud endpoint sync status
|
||||||
|
or management alarm condition depending on strategy type.
|
||||||
|
in: body
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
group_id:
|
group_id:
|
||||||
description: |
|
description: |
|
||||||
The ID of a subcloud group. Default is 1.
|
The ID of a subcloud group. Default is 1.
|
||||||
|
@ -3,5 +3,6 @@
|
|||||||
"type": "patch",
|
"type": "patch",
|
||||||
"stop-on-failure": "true",
|
"stop-on-failure": "true",
|
||||||
"max-parallel-subclouds": 2,
|
"max-parallel-subclouds": 2,
|
||||||
"upload-only": "true"
|
"upload-only": "true",
|
||||||
|
"force": "true"
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,21 @@ class AuditController(object):
|
|||||||
if not payload:
|
if not payload:
|
||||||
pecan.abort(http.client.BAD_REQUEST, _("Body required"))
|
pecan.abort(http.client.BAD_REQUEST, _("Body required"))
|
||||||
|
|
||||||
LOG.debug(f"Payload sent by system controller: {payload}")
|
# TODO(vgluzrom): Remove extra_args from header and keep it only in payload
|
||||||
|
# once all supported dcagent versions have this possibility. If system
|
||||||
|
# controller sends extra_args in payload to a dcagent that doesn't support it,
|
||||||
|
# it will raise an UnsupportedAudit exception.
|
||||||
|
try:
|
||||||
|
headers = json.loads(request.headers.get("X-DCAGENT-HEADERS", "{}"))
|
||||||
|
except ValueError:
|
||||||
|
pecan.abort(http.client.BAD_REQUEST, _("Request headers decoding error"))
|
||||||
|
|
||||||
|
extra_args = payload.pop("extra_args", {})
|
||||||
|
extra_args = {**extra_args, **headers}
|
||||||
|
|
||||||
|
LOG.debug(
|
||||||
|
f"Payload sent by system controller: {payload}. Extra args: {extra_args}"
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Delete "use_cache" from payload so it doesn't get passed as an audit
|
# Delete "use_cache" from payload so it doesn't get passed as an audit
|
||||||
@ -52,7 +66,7 @@ class AuditController(object):
|
|||||||
requested_audit = RequestedAudit(
|
requested_audit = RequestedAudit(
|
||||||
request_token=context.auth_token, use_cache=use_cache
|
request_token=context.auth_token, use_cache=use_cache
|
||||||
)
|
)
|
||||||
return requested_audit.get_sync_status(payload)
|
return requested_audit.get_sync_status(payload, extra_args)
|
||||||
|
|
||||||
except UnsupportedAudit as ex:
|
except UnsupportedAudit as ex:
|
||||||
LOG.exception(ex)
|
LOG.exception(ex)
|
||||||
|
@ -102,9 +102,16 @@ class PeriodicAudit(utils.BaseAuditManager):
|
|||||||
(get_subcloud_base_audit, lambda: [self.sysinv_client, self.fm_client]),
|
(get_subcloud_base_audit, lambda: [self.sysinv_client, self.fm_client]),
|
||||||
(FirmwareAudit.get_subcloud_audit_data, lambda: [self.sysinv_client]),
|
(FirmwareAudit.get_subcloud_audit_data, lambda: [self.sysinv_client]),
|
||||||
(KubernetesAudit.get_subcloud_audit_data, lambda: [self.sysinv_client]),
|
(KubernetesAudit.get_subcloud_audit_data, lambda: [self.sysinv_client]),
|
||||||
|
# Need to call kube rootca function two times as it has a different
|
||||||
|
# response if the subcloud was rehomed or not and we want to cache both
|
||||||
|
# results
|
||||||
(
|
(
|
||||||
KubeRootcaUpdateAudit.get_subcloud_audit_data,
|
KubeRootcaUpdateAudit.get_subcloud_audit_data,
|
||||||
lambda: [self.sysinv_client, self.fm_client],
|
lambda: [self.sysinv_client, self.fm_client, False],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
KubeRootcaUpdateAudit.get_subcloud_audit_data,
|
||||||
|
lambda: [self.sysinv_client, self.fm_client, True],
|
||||||
),
|
),
|
||||||
(SoftwareAudit.get_subcloud_audit_data, lambda: [self.software_client]),
|
(SoftwareAudit.get_subcloud_audit_data, lambda: [self.software_client]),
|
||||||
]
|
]
|
||||||
@ -119,7 +126,7 @@ class RequestedAudit(utils.BaseAuditManager):
|
|||||||
self.request_token = request_token
|
self.request_token = request_token
|
||||||
self.use_cache = use_cache
|
self.use_cache = use_cache
|
||||||
|
|
||||||
def get_single_audit_status(self, audit_type, regionone_audit_data):
|
def get_single_audit_status(self, audit_type, regionone_audit_data, extra_args):
|
||||||
# Since this run in parallel, we need to initialize the clients
|
# Since this run in parallel, we need to initialize the clients
|
||||||
# here to not use the same socket in every call
|
# here to not use the same socket in every call
|
||||||
sysinv_client, fm_client, software_client = self.initialize_clients(
|
sysinv_client, fm_client, software_client = self.initialize_clients(
|
||||||
@ -139,8 +146,9 @@ class RequestedAudit(utils.BaseAuditManager):
|
|||||||
sysinv_client, regionone_audit_data
|
sysinv_client, regionone_audit_data
|
||||||
)
|
)
|
||||||
elif audit_type == dccommon_consts.KUBE_ROOTCA_AUDIT:
|
elif audit_type == dccommon_consts.KUBE_ROOTCA_AUDIT:
|
||||||
|
rehomed = extra_args.get("rehomed", False)
|
||||||
resp = KubeRootcaUpdateAudit.get_subcloud_sync_status(
|
resp = KubeRootcaUpdateAudit.get_subcloud_sync_status(
|
||||||
sysinv_client, fm_client, regionone_audit_data
|
sysinv_client, fm_client, regionone_audit_data, rehomed
|
||||||
)
|
)
|
||||||
elif audit_type == dccommon_consts.KUBERNETES_AUDIT:
|
elif audit_type == dccommon_consts.KUBERNETES_AUDIT:
|
||||||
resp = KubernetesAudit.get_subcloud_sync_status(
|
resp = KubernetesAudit.get_subcloud_sync_status(
|
||||||
@ -161,11 +169,16 @@ class RequestedAudit(utils.BaseAuditManager):
|
|||||||
raise exceptions.AuditStatusFailure(audit=audit_type)
|
raise exceptions.AuditStatusFailure(audit=audit_type)
|
||||||
return audit_type, resp
|
return audit_type, resp
|
||||||
|
|
||||||
def get_sync_status(self, payload):
|
def get_sync_status(self, payload, extra_args):
|
||||||
sync_resp = {}
|
sync_resp = {}
|
||||||
pool = GreenPool(size=10)
|
pool = GreenPool(size=10)
|
||||||
jobs = [
|
jobs = [
|
||||||
pool.spawn(self.get_single_audit_status, audit_type, regionone_audit_data)
|
pool.spawn(
|
||||||
|
self.get_single_audit_status,
|
||||||
|
audit_type,
|
||||||
|
regionone_audit_data,
|
||||||
|
extra_args,
|
||||||
|
)
|
||||||
for audit_type, regionone_audit_data in payload.items()
|
for audit_type, regionone_audit_data in payload.items()
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ from dccommon.drivers import base
|
|||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
DCAGENT_REST_DEFAULT_TIMEOUT = 900
|
DCAGENT_REST_DEFAULT_TIMEOUT = 30
|
||||||
|
|
||||||
|
|
||||||
class DcagentClient(base.DriverBase):
|
class DcagentClient(base.DriverBase):
|
||||||
@ -37,11 +37,17 @@ class DcagentClient(base.DriverBase):
|
|||||||
else:
|
else:
|
||||||
self.endpoint = endpoint
|
self.endpoint = endpoint
|
||||||
|
|
||||||
def audit(self, audit_data, timeout=DCAGENT_REST_DEFAULT_TIMEOUT):
|
def audit(
|
||||||
|
self,
|
||||||
|
audit_data: dict,
|
||||||
|
headers: dict = None,
|
||||||
|
timeout: int = DCAGENT_REST_DEFAULT_TIMEOUT,
|
||||||
|
):
|
||||||
"""Audit subcloud"""
|
"""Audit subcloud"""
|
||||||
url = self.endpoint + "/v1/dcaudit"
|
url = self.endpoint + "/v1/dcaudit"
|
||||||
|
headers = headers or {}
|
||||||
response = self.session.patch(
|
response = self.session.patch(
|
||||||
url, json=audit_data, timeout=timeout, raise_exc=False
|
url, json=audit_data, headers=headers, timeout=timeout, raise_exc=False
|
||||||
)
|
)
|
||||||
|
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
|
@ -87,18 +87,22 @@ class KubeRootcaUpdateAudit(object):
|
|||||||
cls,
|
cls,
|
||||||
sysinv_client: SysinvClient,
|
sysinv_client: SysinvClient,
|
||||||
fm_client: FmClient,
|
fm_client: FmClient,
|
||||||
|
rehomed: bool = False,
|
||||||
subcloud_name: str = None,
|
subcloud_name: str = None,
|
||||||
) -> tuple:
|
) -> tuple:
|
||||||
skip_audit = 2 * [dccommon_consts.SKIP_AUDIT]
|
skip_audit = 2 * [dccommon_consts.SKIP_AUDIT]
|
||||||
try:
|
if rehomed:
|
||||||
success, subcloud_cert_data = sysinv_client.get_kube_rootca_cert_id()
|
try:
|
||||||
except Exception:
|
success, subcloud_cert_data = sysinv_client.get_kube_rootca_cert_id()
|
||||||
msg = f"Failed to get Kubernetes root CA status, skip {AUDIT_TYPE} audit."
|
except Exception:
|
||||||
log_subcloud_msg(LOG.exception, msg, subcloud_name)
|
msg = (
|
||||||
return skip_audit
|
f"Failed to get Kubernetes root CA status, skip {AUDIT_TYPE} audit."
|
||||||
|
)
|
||||||
|
log_subcloud_msg(LOG.exception, msg, subcloud_name)
|
||||||
|
return skip_audit
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
return CERT_BASED, subcloud_cert_data
|
return CERT_BASED, subcloud_cert_data
|
||||||
|
|
||||||
try:
|
try:
|
||||||
detected_alarms = fm_client.get_alarms_by_ids(KUBE_ROOTCA_ALARM_LIST)
|
detected_alarms = fm_client.get_alarms_by_ids(KUBE_ROOTCA_ALARM_LIST)
|
||||||
@ -114,12 +118,13 @@ class KubeRootcaUpdateAudit(object):
|
|||||||
sysinv_client: SysinvClient,
|
sysinv_client: SysinvClient,
|
||||||
fm_client: FmClient,
|
fm_client: FmClient,
|
||||||
regionone_rootca_certid: str,
|
regionone_rootca_certid: str,
|
||||||
|
rehomed: bool = False,
|
||||||
subcloud_name: str = None,
|
subcloud_name: str = None,
|
||||||
):
|
):
|
||||||
"""Get the sync status of the subcloud's kube root CA cert."""
|
"""Get the sync status of the subcloud's kube root CA cert."""
|
||||||
|
|
||||||
audit_method, subcloud_audit_data = cls.get_subcloud_audit_data(
|
audit_method, subcloud_audit_data = cls.get_subcloud_audit_data(
|
||||||
sysinv_client, fm_client, subcloud_name
|
sysinv_client, fm_client, rehomed, subcloud_name
|
||||||
)
|
)
|
||||||
|
|
||||||
sync_status = None
|
sync_status = None
|
||||||
@ -147,8 +152,10 @@ class KubeRootcaUpdateAudit(object):
|
|||||||
|
|
||||||
The audit logic is as follow:
|
The audit logic is as follow:
|
||||||
No region one cert ID -> skip audit
|
No region one cert ID -> skip audit
|
||||||
Subcloud doesn't have the API to get cert ID -> alarm based
|
Failure to get alarms or subcloud cert ID -> skip audit
|
||||||
Subcloud has the API to get cert ID -> cert based
|
Subcloud was not rehomed -> alarm based
|
||||||
|
Subcloud was rehomed and doesn't have the API to get cert ID -> alarm based
|
||||||
|
Subcloud was rehomed and has the API to get cert ID -> cert based
|
||||||
|
|
||||||
:param sysinv_client: the sysinv client object
|
:param sysinv_client: the sysinv client object
|
||||||
:param fm_client: the fm client object
|
:param fm_client: the fm client object
|
||||||
@ -165,7 +172,11 @@ class KubeRootcaUpdateAudit(object):
|
|||||||
return dccommon_consts.SYNC_STATUS_IN_SYNC
|
return dccommon_consts.SYNC_STATUS_IN_SYNC
|
||||||
|
|
||||||
sync_status = self.get_subcloud_sync_status(
|
sync_status = self.get_subcloud_sync_status(
|
||||||
sysinv_client, fm_client, regionone_rootca_certid, subcloud.name
|
sysinv_client,
|
||||||
|
fm_client,
|
||||||
|
regionone_rootca_certid,
|
||||||
|
subcloud.rehomed,
|
||||||
|
subcloud.name,
|
||||||
)
|
)
|
||||||
|
|
||||||
if sync_status:
|
if sync_status:
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
@ -357,6 +358,13 @@ class SubcloudAuditWorkerManager(manager.Manager):
|
|||||||
audit_payload["use_cache"] = use_cache
|
audit_payload["use_cache"] = use_cache
|
||||||
return audit_payload
|
return audit_payload
|
||||||
|
|
||||||
|
def _build_dcagent_request_headers(self, subcloud: models.Subcloud):
|
||||||
|
dc_agent_headers = {}
|
||||||
|
if subcloud.rehomed:
|
||||||
|
dc_agent_headers["rehomed"] = subcloud.rehomed
|
||||||
|
header = {"X-DCAGENT-HEADERS": json.dumps(dc_agent_headers)}
|
||||||
|
return header
|
||||||
|
|
||||||
def _update_sw_sync_status_from_deploy_status(self, subcloud, audit_results):
|
def _update_sw_sync_status_from_deploy_status(self, subcloud, audit_results):
|
||||||
# If the subcloud deploy_status is in any of the following states,
|
# If the subcloud deploy_status is in any of the following states,
|
||||||
# the sync_status should be set to out-of-sync for software audit.
|
# the sync_status should be set to out-of-sync for software audit.
|
||||||
@ -541,9 +549,10 @@ class SubcloudAuditWorkerManager(manager.Manager):
|
|||||||
do_software_audit,
|
do_software_audit,
|
||||||
use_cache,
|
use_cache,
|
||||||
)
|
)
|
||||||
|
headers = self._build_dcagent_request_headers(subcloud)
|
||||||
audit_results = {}
|
audit_results = {}
|
||||||
try:
|
try:
|
||||||
audit_results = dcagent_client.audit(audit_payload)
|
audit_results = dcagent_client.audit(audit_payload, headers)
|
||||||
except Exception:
|
except Exception:
|
||||||
LOG.exception(failmsg % (subcloud.name, "dcagent"))
|
LOG.exception(failmsg % (subcloud.name, "dcagent"))
|
||||||
failures.append("dcagent")
|
failures.append("dcagent")
|
||||||
|
@ -248,6 +248,7 @@ class SwUpdateManager(manager.Manager):
|
|||||||
max_parallel_subclouds = int(max_parallel_subclouds_str)
|
max_parallel_subclouds = int(max_parallel_subclouds_str)
|
||||||
|
|
||||||
stop_on_failure = payload.get("stop-on-failure") in ["true"]
|
stop_on_failure = payload.get("stop-on-failure") in ["true"]
|
||||||
|
force = payload.get(consts.EXTRA_ARGS_FORCE) in ["true"]
|
||||||
|
|
||||||
# Has the user specified a specific subcloud?
|
# Has the user specified a specific subcloud?
|
||||||
cloud_name = payload.get("cloud_name")
|
cloud_name = payload.get("cloud_name")
|
||||||
@ -257,7 +258,6 @@ class SwUpdateManager(manager.Manager):
|
|||||||
# Has the user specified for_sw_deploy flag for prestage strategy?
|
# Has the user specified for_sw_deploy flag for prestage strategy?
|
||||||
if strategy_type == consts.SW_UPDATE_TYPE_PRESTAGE:
|
if strategy_type == consts.SW_UPDATE_TYPE_PRESTAGE:
|
||||||
for_sw_deploy = payload.get(consts.PRESTAGE_FOR_SW_DEPLOY) in ["true"]
|
for_sw_deploy = payload.get(consts.PRESTAGE_FOR_SW_DEPLOY) in ["true"]
|
||||||
force = payload.get(consts.EXTRA_ARGS_FORCE) in ["true"]
|
|
||||||
|
|
||||||
if cloud_name:
|
if cloud_name:
|
||||||
# Make sure subcloud exists
|
# Make sure subcloud exists
|
||||||
@ -282,7 +282,7 @@ class SwUpdateManager(manager.Manager):
|
|||||||
raise exceptions.BadRequest(resource="strategy", msg=str(ex))
|
raise exceptions.BadRequest(resource="strategy", msg=str(ex))
|
||||||
else:
|
else:
|
||||||
self.strategy_validators[strategy_type].validate_strategy_requirements(
|
self.strategy_validators[strategy_type].validate_strategy_requirements(
|
||||||
context, subcloud.id, subcloud.name
|
context, subcloud.id, subcloud.name, force
|
||||||
)
|
)
|
||||||
|
|
||||||
extra_args = None
|
extra_args = None
|
||||||
@ -328,7 +328,7 @@ class SwUpdateManager(manager.Manager):
|
|||||||
single_group.id if subcloud_group else None,
|
single_group.id if subcloud_group else None,
|
||||||
cloud_name,
|
cloud_name,
|
||||||
self.strategy_validators[strategy_type].build_availability_status_filter(),
|
self.strategy_validators[strategy_type].build_availability_status_filter(),
|
||||||
self.strategy_validators[strategy_type].build_sync_status_filter(),
|
self.strategy_validators[strategy_type].build_sync_status_filter(force),
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO(rlima): move this step to validators
|
# TODO(rlima): move this step to validators
|
||||||
|
@ -20,17 +20,24 @@ class StrategyValidationBase(object):
|
|||||||
"""Base class for strategy validation"""
|
"""Base class for strategy validation"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
self.accepts_force = False
|
||||||
self.endpoint_type = None
|
self.endpoint_type = None
|
||||||
|
|
||||||
def validate_strategy_requirements(self, context, subcloud_id, subcloud_name):
|
def validate_strategy_requirements(
|
||||||
|
self, context, subcloud_id, subcloud_name, force=False
|
||||||
|
):
|
||||||
"""Validates the requirements for a strategy
|
"""Validates the requirements for a strategy
|
||||||
|
|
||||||
:param context: request context object
|
:param context: request context object
|
||||||
:param subcloud_id: subcloud's id
|
:param subcloud_id: subcloud's id
|
||||||
:param subcloud_name: subcloud's name
|
:param subcloud_name: subcloud's name
|
||||||
|
:param force: if the strategy should be forced to execute
|
||||||
:raises BadRequest: if the requirements for the strategy are not met
|
:raises BadRequest: if the requirements for the strategy are not met
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if self.accepts_force and force:
|
||||||
|
return
|
||||||
|
|
||||||
subcloud_status = db_api.subcloud_status_get(
|
subcloud_status = db_api.subcloud_status_get(
|
||||||
context, subcloud_id, self.endpoint_type
|
context, subcloud_id, self.endpoint_type
|
||||||
)
|
)
|
||||||
@ -64,9 +71,10 @@ class StrategyValidationBase(object):
|
|||||||
|
|
||||||
return dccommon_consts.AVAILABILITY_ONLINE
|
return dccommon_consts.AVAILABILITY_ONLINE
|
||||||
|
|
||||||
def build_sync_status_filter(self):
|
def build_sync_status_filter(self, force):
|
||||||
"""Builds the sync status filter for valid subclouds
|
"""Builds the sync status filter for valid subclouds
|
||||||
|
|
||||||
|
:param force: if the strategy should be forced to execute
|
||||||
:return: sync status to filter
|
:return: sync status to filter
|
||||||
:rtype: list
|
:rtype: list
|
||||||
"""
|
"""
|
||||||
|
@ -26,6 +26,7 @@ class KubeRootCaStrategyValidator(StrategyValidationBase):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.endpoint_type = dccommon_consts.ENDPOINT_TYPE_KUBE_ROOTCA
|
self.endpoint_type = dccommon_consts.ENDPOINT_TYPE_KUBE_ROOTCA
|
||||||
|
self.accepts_force = True
|
||||||
|
|
||||||
def build_extra_args(self, payload):
|
def build_extra_args(self, payload):
|
||||||
"""Builds the extra args for a strategy
|
"""Builds the extra args for a strategy
|
||||||
@ -40,3 +41,18 @@ class KubeRootCaStrategyValidator(StrategyValidationBase):
|
|||||||
consts.EXTRA_ARGS_SUBJECT: payload.get(consts.EXTRA_ARGS_SUBJECT),
|
consts.EXTRA_ARGS_SUBJECT: payload.get(consts.EXTRA_ARGS_SUBJECT),
|
||||||
consts.EXTRA_ARGS_CERT_FILE: payload.get(consts.EXTRA_ARGS_CERT_FILE),
|
consts.EXTRA_ARGS_CERT_FILE: payload.get(consts.EXTRA_ARGS_CERT_FILE),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def build_sync_status_filter(self, force):
|
||||||
|
"""Builds the sync status filter for valid subclouds
|
||||||
|
|
||||||
|
:param force: if the strategy should be forced to execute
|
||||||
|
:return: sync status to filter
|
||||||
|
:rtype: list
|
||||||
|
"""
|
||||||
|
|
||||||
|
if force:
|
||||||
|
return [
|
||||||
|
dccommon_consts.SYNC_STATUS_IN_SYNC,
|
||||||
|
dccommon_consts.SYNC_STATUS_OUT_OF_SYNC,
|
||||||
|
]
|
||||||
|
return [dccommon_consts.SYNC_STATUS_OUT_OF_SYNC]
|
||||||
|
@ -44,9 +44,10 @@ class PatchStrategyValidator(StrategyValidationBase):
|
|||||||
consts.EXTRA_ARGS_REMOVE: remove_bool,
|
consts.EXTRA_ARGS_REMOVE: remove_bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
def build_sync_status_filter(self):
|
def build_sync_status_filter(self, force):
|
||||||
"""Builds the sync status filter for valid subclouds
|
"""Builds the sync status filter for valid subclouds
|
||||||
|
|
||||||
|
:param force: if the strategy should be forced to execute
|
||||||
:return: sync status to filter
|
:return: sync status to filter
|
||||||
:rtype: list
|
:rtype: list
|
||||||
"""
|
"""
|
||||||
|
@ -30,7 +30,7 @@ class PrestageStrategyValidator(StrategyValidationBase):
|
|||||||
self.endpoint_type = dccommon_consts.AUDIT_TYPE_SOFTWARE
|
self.endpoint_type = dccommon_consts.AUDIT_TYPE_SOFTWARE
|
||||||
|
|
||||||
# TODO(rlima): move prestage validations here
|
# TODO(rlima): move prestage validations here
|
||||||
def build_sync_status_filter(self):
|
def build_sync_status_filter(self, force):
|
||||||
"""Builds the sync status filter for valid subclouds
|
"""Builds the sync status filter for valid subclouds
|
||||||
|
|
||||||
:param force: if the strategy should be forced to execute
|
:param force: if the strategy should be forced to execute
|
||||||
|
@ -53,37 +53,37 @@ SUBCLOUD_1 = {
|
|||||||
"name": "subcloud1",
|
"name": "subcloud1",
|
||||||
"region_name": "2ec93dfb654846909efe61d1b39dd2ce",
|
"region_name": "2ec93dfb654846909efe61d1b39dd2ce",
|
||||||
"rehomed": True,
|
"rehomed": True,
|
||||||
"software_version": "22.12",
|
"software_version": "24.09",
|
||||||
}
|
}
|
||||||
SUBCLOUD_2 = {
|
SUBCLOUD_2 = {
|
||||||
"name": "subcloud2",
|
"name": "subcloud2",
|
||||||
"region_name": "ca2761ee7aa34cbe8415ec9a3c86854f",
|
"region_name": "ca2761ee7aa34cbe8415ec9a3c86854f",
|
||||||
"rehomed": True,
|
"rehomed": True,
|
||||||
"software_version": "22.12",
|
"software_version": "24.09",
|
||||||
}
|
}
|
||||||
SUBCLOUD_3 = {
|
SUBCLOUD_3 = {
|
||||||
"name": "subcloud3",
|
"name": "subcloud3",
|
||||||
"region_name": "659e12e5f7ad411abfcd83f5cedca0bf",
|
"region_name": "659e12e5f7ad411abfcd83f5cedca0bf",
|
||||||
"rehomed": True,
|
"rehomed": True,
|
||||||
"software_version": "21.12",
|
"software_version": "22.12",
|
||||||
}
|
}
|
||||||
SUBCLOUD_4 = {
|
SUBCLOUD_4 = {
|
||||||
"name": "subcloud4",
|
"name": "subcloud4",
|
||||||
"region_name": "c25f3b0553384104b664789bd93a2ba8",
|
"region_name": "c25f3b0553384104b664789bd93a2ba8",
|
||||||
"rehomed": False,
|
"rehomed": False,
|
||||||
"software_version": "21.12",
|
"software_version": "22.12",
|
||||||
}
|
}
|
||||||
SUBCLOUD_5 = {
|
SUBCLOUD_5 = {
|
||||||
"name": "subcloud5",
|
"name": "subcloud5",
|
||||||
"region_name": "809581dc2d154e008480bac1f43b7aff",
|
"region_name": "809581dc2d154e008480bac1f43b7aff",
|
||||||
"rehomed": False,
|
"rehomed": False,
|
||||||
"software_version": "21.12",
|
"software_version": "22.12",
|
||||||
}
|
}
|
||||||
SUBCLOUD_6 = {
|
SUBCLOUD_6 = {
|
||||||
"name": "subcloud6",
|
"name": "subcloud6",
|
||||||
"region_name": "8c60b99f3e1245b7bc5a049802ade8d2",
|
"region_name": "8c60b99f3e1245b7bc5a049802ade8d2",
|
||||||
"rehomed": False,
|
"rehomed": False,
|
||||||
"software_version": "22.12",
|
"software_version": "24.09",
|
||||||
}
|
}
|
||||||
SUBCLOUD_7 = {"name": "subcloud7", "region_name": "9fde6dca22fa422bb1e8cf03bedc18e4"}
|
SUBCLOUD_7 = {"name": "subcloud7", "region_name": "9fde6dca22fa422bb1e8cf03bedc18e4"}
|
||||||
SUBCLOUD_8 = {"name": "subcloud8", "region_name": "f3cb0b109c4543fda3ed50ed5783279d"}
|
SUBCLOUD_8 = {"name": "subcloud8", "region_name": "f3cb0b109c4543fda3ed50ed5783279d"}
|
||||||
|
@ -26,6 +26,7 @@ class FakeSubcloudObj(object):
|
|||||||
def __init__(self, subcloud_dict):
|
def __init__(self, subcloud_dict):
|
||||||
self.name = subcloud_dict["name"]
|
self.name = subcloud_dict["name"]
|
||||||
self.region_name = subcloud_dict["region_name"]
|
self.region_name = subcloud_dict["region_name"]
|
||||||
|
self.rehomed = subcloud_dict["rehomed"]
|
||||||
self.software_version = subcloud_dict["software_version"]
|
self.software_version = subcloud_dict["software_version"]
|
||||||
|
|
||||||
|
|
||||||
@ -225,6 +226,9 @@ class TestKubeRootcaUpdateAudit(base.DCManagerTestCase):
|
|||||||
self.mock_sysinv_client().get_kube_rootca_cert_id.return_value = (
|
self.mock_sysinv_client().get_kube_rootca_cert_id.return_value = (
|
||||||
base.FakeException("API cert ID request failed")
|
base.FakeException("API cert ID request failed")
|
||||||
)
|
)
|
||||||
|
self.mock_fm_client().get_alarms_by_ids.side_effect = base.FakeException(
|
||||||
|
"get_alarms_by_ids failed"
|
||||||
|
)
|
||||||
|
|
||||||
response = self.audit.subcloud_kube_rootca_audit(
|
response = self.audit.subcloud_kube_rootca_audit(
|
||||||
self.mock_sysinv_client(),
|
self.mock_sysinv_client(),
|
||||||
@ -234,3 +238,36 @@ class TestKubeRootcaUpdateAudit(base.DCManagerTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(response, None)
|
self.assertEqual(response, None)
|
||||||
|
|
||||||
|
def test_kube_rootca_update_audit_method(self):
|
||||||
|
"""Test if kube-rootca is auditing correctly based using alarm or cert_id"""
|
||||||
|
# Set the region one data
|
||||||
|
self.kube_rootca_cert_id.return_value = (
|
||||||
|
True,
|
||||||
|
FakeKubeRootcaData("cert1", ""),
|
||||||
|
)
|
||||||
|
kube_rootca_update_audit_data = self.get_rootca_audit_data()
|
||||||
|
|
||||||
|
subclouds = [base.SUBCLOUD_1, base.SUBCLOUD_2]
|
||||||
|
for subcloud_dict in subclouds:
|
||||||
|
subcloud = FakeSubcloudObj(subcloud_dict)
|
||||||
|
|
||||||
|
self.kube_rootca_cert_id.return_value = True, FakeKubeRootcaData(
|
||||||
|
"cert1", ""
|
||||||
|
)
|
||||||
|
self.mock_sysinv_client().get_kube_rootca_cert_id.return_value = (
|
||||||
|
True,
|
||||||
|
FakeKubeRootcaData("cert1", ""),
|
||||||
|
)
|
||||||
|
self.mock_fm_client().get_alarms_by_ids.return_value = None
|
||||||
|
|
||||||
|
self.audit.subcloud_kube_rootca_audit(
|
||||||
|
self.mock_sysinv_client(),
|
||||||
|
self.mock_fm_client(),
|
||||||
|
subcloud,
|
||||||
|
kube_rootca_update_audit_data,
|
||||||
|
)
|
||||||
|
if subcloud.rehomed:
|
||||||
|
self.mock_sysinv_client().get_kube_rootca_cert_id.assert_called()
|
||||||
|
else:
|
||||||
|
self.mock_fm_client().get_alarms_by_ids.assert_called()
|
||||||
|
Loading…
Reference in New Issue
Block a user