Implement system_config_update orchestration

This commit adds VIM orchestration for system config update to drive the
host swact/lock/unlock once these operations are expected to update the
system config.

CLI: sw-manager kube-rootca-update-strategy
    apply create delete show

Test plan:
1. Create a system config udpate strategy successfully. --passed
2. Create a system config update strategy failed if the host resource
doesn't exist. --passed
3. Create a system config update strategy failed if an unexpected alarm
exists and the strategy alarm restrictions is set as strict. --passed
4. Create a system config update strategy successfully if an unexpected
alarm exists and the strategy alarm restrictions is set as relax.
--passed
5. Create a system config update strategy failed if a controller offline
in a DX system. --passed
6. Create a system config update strategy failed if a storage offline in
a standard system. --passed
7. Create a system config update strategy successfully if a worker
offline in a standard system. --passed
8. Apply a system config update strategy successfully. --passed
9. Apply a system config update strategy failed if a host failed to
lock. --passed
10. Delete a system config update strategy successful if a the strategy
is complete or failed. --passed
11. Create a system config update strategy with strategy not required
for the host in k8s, verify the host is excluded from the strategy.

Story: 2010719
Task: 47910

Change-Id: I052bc5b2004f17de870a81c523d0a1f4e422a902
Signed-off-by: Yuxing Jiang <Yuxing.Jiang@windriver.com>
This commit is contained in:
Yuxing Jiang 2023-05-16 17:32:51 -04:00
parent 3bd5eed446
commit 6dba3df3e3
45 changed files with 3220 additions and 54 deletions

View File

@ -118,6 +118,10 @@ forbidden (403), badMethod (405), overLimit (413), itemNotFound (404)
{
"href": "http://192.168.204.2:4545/orchestration/fw-update/",
"rel": "fw-update"
},
{
"href": "http://192.168.204.2:4545/orchestration/system-config-update/",
"rel": "system-config-update"
}
]
}
@ -223,6 +227,39 @@ forbidden (403), badMethod (405), overLimit (413), itemNotFound (404)
This operation does not accept a request body.
*********************************************************************************
Lists information about all NFV VIM API orchestration system-config-update links
*********************************************************************************
.. rest_method:: GET /api/orchestration/system-config-update
**Normal response codes**
200
**Error response codes**
serviceUnavailable (503), badRequest (400), unauthorized (401),
forbidden (403), badMethod (405), overLimit (413), itemNotFound (404)
::
{
"id": "system-config-update",
"links": [
{
"href": "http://192.168.204.2:4545/orchestration/system-config-update/",
"rel": "self"
},
{
"href": "http://192.168.204.2:4545/orchestration/system-config-update/strategy/",
"rel": "strategy"
}
]
}
This operation does not accept a request body.
---------------
Patch Strategy
---------------
@ -3095,3 +3132,652 @@ forbidden (403), badMethod (405), overLimit (413)
}
}
------------------------------
System Config Update Strategy
------------------------------
System config update orchestration is done with a system config update
orchestration strategy, or plan, for the automated update procedure which
contains a number of parameters for customizing the particular behavior of the
system config update orchestration.
***************************************************************************
Shows detailed information about the current system-config-update strategy
***************************************************************************
.. rest_method:: GET /api/orchestration/system-config-update/strategy
**Normal response codes**
200
**Error response codes**
serviceUnavailable (503), badRequest (400), unauthorized (401),
forbidden (403), badMethod (405), overLimit (413), itemNotFound (404)
::
{
"strategy": {
"controller-apply-type": "serial",
"swift-apply-type": "ignore",
"storage-apply-type": "serial",
"worker-apply-type": "parallel",
"state": "ready-to-apply",
"default-instance-action": "stop-start",
"max-parallel-worker-hosts": 4,
"alarm-restrictions": "strict",
"current-phase-completion-percentage": 100,
"uuid": "5dd16d94-dfc5-4029-bfcb-d815e7c2dc3d",
"name": "system-config-update",
"current-phase": "build",
"build-phase": {
"phase-name": "build",
"current-stage": 1,
"total-stages": 1,
"completion-percentage": 100,
"start-date-time": "",
"end-date-time": "",
"stop-at-stage": 1,
"result": "success",
"timeout": 182,
"reason": "",
"inprogress": false,
"stages": [
{
"stage-id": 0,
"total-steps": 3,
"stage-name": "system-config-update-hosts-query",
"result": "success",
"timeout": 181,
"inprogress": false,
"start-date-time": "",
"end-date-time": "",
"reason": "",
"current-step" : 3,
"steps":[
{
"step-id": 0,
"step-name": "query-alarms",
"entity-type": "",
"entity-names": [],
"entity-uuids": [],
"start-date-time": "",
"end-date-time": "",
"timeout": 60,
"result": "success",
"reason": ""
},
{
"step-id": 1,
"step-name": "query-strategy-required",
"entity-type": "",
"entity-names": [],
"entity-uuids": [],
"start-date-time": "",
"end-date-time": "",
"timeout": 60,
"result": "success",
"reason": ""
},
{
"step-id": 2,
"step-name": "query-in-sync",
"entity-type": "",
"entity-names": [],
"entity-uuids": [],
"start-date-time": "",
"end-date-time": "",
"timeout": 60,
"result": "success",
"reason": ""
}
]
}
]
},
"apply-phase": {
"phase-name": "apply",
"current-stage": 0,
"completion-percentage": 100,
"total-stages": 2,
"stop-at-stage": 0,
"start-date-time": "",
"end-date-time": "",
"result": "initial",
"timeout": 0,
"reason": "",
"inprogress": false,
"stages": [
{
"stage-id": 0,
"stage-name": "system-config-update-controllers",
"start-date-time": "",
"end-date-time": "",
"current-step": 0,
"result": "initial",
"timeout": 6436,
"inprogress": false,
"reason": "",
"total-steps": 6,
"steps": [
{
"step-id": 0,
"step-name": "query-alarms",
"entity-type": "",
"entity-names": [],
"entity-uuids": [],
"start-date-time": "",
"end-date-time": "",
"timeout": 60,
"result": "initial",
"reason": ""
},
{
"start-date-time": "",
"end-date-time": "",
"timeout": 900,
"entity-type": "hosts",
"step-id": 1,
"entity-uuids": [
"523cbd2d-f7f8-4707-8617-d085386f8711"
],
"step-name": "swact-hosts",
"result": "initial",
"entity-names": [
"controller-1"
],
"reason": ""
},
{
"start-date-time": "",
"end-date-time": "",
"timeout": 900,
"entity-type": "hosts",
"step-id": 2,
"entity-uuids": [
"523cbd2d-f7f8-4707-8617-d085386f8711"
],
"step-name": "lock-hosts",
"result": "initial",
"entity-names": [
"controller-1"
],
"reason": ""
},
{
"start-date-time": "",
"end-date-time": "",
"timeout": 1800,
"entity-type": "hosts",
"step-id": 3,
"entity-uuids": [
"523cbd2d-f7f8-4707-8617-d085386f8711"
],
"step-name": "config-disabled-host",
"result": "initial",
"entity-names": [
"controller-1"
],
"reason": ""
},
{
"start-date-time": "",
"end-date-time": "",
"timeout": 900,
"entity-type": "hosts",
"step-id": 4,
"entity-uuids": [
"523cbd2d-f7f8-4707-8617-d085386f8711"
],
"step-name": "unlock-hosts",
"result": "initial",
"entity-names": [
"controller-1"
],
"reason": ""
},
{
"step-id": 5,
"entity-type": "",
"step-name": "system-stabilize",
"entity-names": [],
"entity-uuids": [],
"start-date-time": "",
"end-date-time": "",
"timeout": 60,
"result": "initial",
"reason": ""
}
],
},
{
"stage-id": 1,
"total-steps": 6,
"stage-name": "system-config-update-controllers",
"inprogress": false,
"start-date-time": "",
"end-date-time": "",
"timeout": 6436,
"reason": "",
"result": "initial",
"current-step": 0,
"steps":[
{
"step-id": 0,
"step-name": "query-alarms",
"entity-type": "",
"entity-names": [],
"entity-uuids": [],
"start-date-time": "",
"end-date-time": "",
"timeout": 60,
"result": "initial",
"reason": ""
},
{
"start-date-time": "",
"end-date-time": "",
"timeout": 900,
"entity-type": "hosts",
"step-id": 1,
"entity-uuids": [
"0f3715c0-fecd-46e0-9cd0-4fbb31810393"
],
"step-name": "swact-hosts",
"result": "initial",
"entity-names": [
"controller-0"
],
"reason": ""
},
{
"start-date-time": "",
"end-date-time": "",
"timeout": 900,
"entity-type": "hosts",
"step-id": 2,
"entity-uuids": [
"0f3715c0-fecd-46e0-9cd0-4fbb31810393"
],
"step-name": "lock-hosts",
"result": "initial",
"entity-names": [
"controller-0"
],
"reason": ""
},
{
"start-date-time": "",
"end-date-time": "",
"timeout": 1800,
"entity-type": "hosts",
"step-id": 3,
"entity-uuids": [
"0f3715c0-fecd-46e0-9cd0-4fbb31810393"
],
"step-name": "config-disabled-host",
"result": "initial",
"entity-names": [
"controller-0"
],
"reason": ""
},
{
"start-date-time": "",
"end-date-time": "",
"timeout": 900,
"entity-type": "hosts",
"step-id": 4,
"entity-uuids": [
"0f3715c0-fecd-46e0-9cd0-4fbb31810393"
],
"step-name": "unlock-hosts",
"result": "initial",
"entity-names": [
"controller-0"
],
"reason": ""
},
{
"step-id": 5,
"entity-type": "",
"step-name": "system-stabilize",
"entity-names": [],
"entity-uuids": [],
"start-date-time": "",
"end-date-time": "",
"timeout": 60,
"result": "initial",
"reason": ""
}
],
}
],
},
"abort-phase": {
"phase-name": "abort",
"total-stages": 0,
"completion-percentage": 100,
"start-date-time": "",
"end-date-time": "",
"stop-at-stage": 0,
"result": "initial",
"timeout": 0,
"reason": "",
"inprogress": false,
"stages": [],
"current-stage": 0
}
}
}
This operation does not accept a request body.
****************************************
Creates a system-config-update strategy
****************************************
.. rest_method:: POST /api/orchestration/system-config-update/strategy
**Normal response codes**
200
**Error response codes**
serviceUnavailable (503), badRequest (400), unauthorized (401),
forbidden (403), badMethod (405), overLimit (413)
**Request parameters**
.. csv-table::
:header: "Parameter", "Style", "Type", "Description"
:widths: 20, 20, 20, 60
"controller-apply-type", "plain", "xsd:string", "The apply type for controller hosts: ``serial`` or ``ignore``."
"storage-apply-type", "plain", "xsd:string", "The apply type for storage hosts: ``serial`` or ``ignore``."
"worker-apply-type", "plain", "xsd:string", "The apply type for worker hosts: ``serial``, ``parallel`` or ``ignore``."
"max-parallel-worker-hosts (Optional)", "plain", "xsd:integer", "The maximum number of worker hosts to patch in parallel; only applicable if ``worker-apply-type = parallel``. Default value is ``2``."
"default-instance-action", "plain", "xsd:string", "The default instance action: ``stop-start`` or ``migrate``."
"alarm-restrictions (Optional)", "plain", "xsd:string", "The strictness of alarm checks: ``strict`` or ``relaxed``."
::
{
"controller-apply-type": "serial",
"storage-apply-type": "ignore",
"worker-apply-type": "serial",
"default-instance-action": "stop-start",
"alarm-restrictions": "strict",
}
::
{
"strategy": {
"name": "system-config-update",
"worker-apply-type": "serial",
"controller-apply-type": "serial",
"swift-apply-type": "ignore",
"storage-apply-type": "ignore",
"current-phase-completion-percentage": 0,
"uuid": "447c4267-0ecb-48f4-9237-1d747a3e7cca",
"default-instance-action": "stop-start",
"max-parallel-worker-hosts": 2,
"alarm-restrictions": "strict",
"state": "building",
"build-phase": {
"phase-name": "build",
"current-stage": 0,
"start-date-time": "",
"end-date-time": "",
"completion-percentage": 0,
"stop-at-stage": 3,
"result": "inprogress",
"timeout": 182,
"reason": "",
"inprogress": true,
"total-stages": 3,
"stages": [
{
"stage-id": 0,
"stage-name": "system-config-update-query",
"total-steps": 3,
"inprogress": true,
"start-date-time": "",
"end-date-time": "",
"reason": "",
"current-step": 0,
"result": "inprogress",
"timeout": 181,
"steps": [
{
"step-id": 0,
"step-name": "query-alarms",
"entity-type": "",
"entity-names": [],
"entity-uuids": [],
"start-date-time": "",
"end-date-time": "",
"timeout": 60,
"result": "success",
"reason": ""
},
{
"step-id": 1,
"step-name": "query-strategy-required",
"entity-type": "",
"entity-names": [],
"entity-uuids": [],
"start-date-time": "",
"end-date-time": "",
"timeout": 60,
"result": "success",
"reason": ""
},
{
"step-id": 2,
"step-name": "query-in-sync",
"entity-type": "",
"entity-names": [],
"entity-uuids": [],
"start-date-time": "",
"end-date-time": "",
"timeout": 60,
"result": "success",
"reason": ""
}
],
}
],
},
"apply-phase": {
"start-date-time": "",
"end-date-time": "",
"phase-name": "apply",
"completion-percentage": 100,
"total-stages": 0,
"stop-at-stage": 0,
"result": "initial",
"timeout": 0,
"reason": "",
"inprogress": false,
"stages": [],
"current-stage": 0
},
"abort-phase": {
"start-date-time": "",
"end-date-time": "",
"phase-name": "abort",
"completion-percentage": 100,
"total-stages": 0,
"stop-at-stage": 0,
"result": "initial",
"timeout": 0,
"reason": "",
"inprogress":false,
"stages": [],
"current-stage": 0
}
}
}
**************************************************
Deletes the current system-config-update strategy
**************************************************
.. rest_method:: DELETE /api/orchestration/system-config-update/strategy
**Normal response codes**
204
::
{
}
**************************************************
Applies or aborts a system-config-update strategy
**************************************************
.. rest_method:: POST /api/orchestration/system-config-update/strategy/actions
**Normal response codes**
202
**Error response codes**
serviceUnavailable (503), badRequest (400), unauthorized (401),
forbidden (403), badMethod (405), overLimit (413)
**Request parameters**
.. csv-table::
:header: "Parameter", "Style", "Type", "Description"
:widths: 20, 20, 20, 60
"action", "plain", "xsd:string", "The action to take: ``apply-all``, ``apply-stage``, ``abort`` or ``abort-stage``."
"stage-id (Optional)", "plain", "xsd:string", "The stage-id to apply or abort. Only used with ``apply-stage`` or ``abort-stage`` actions."
::
{
"action": "apply-all"
}
::
{
"strategy":{
"controller-apply-type": "serial",
"swift-apply-type": "ignore",
"current-phase-completion-percentage": 0,
"uuid": "447c4267-0ecb-48f4-9237-1d747a3e7cca",
"name": "system-config-update",
"current-phase": "build",
"storage-apply-type": "ignore",
"state":"building",
"worker-apply-type": "serial",
"default-instance-action": "stop-start",
"max-parallel-worker-hosts": 2,
"alarm-restrictions": "strict",
"build-phase": {
"phase-name": "build",
"current-stage": 0,
"start-date-time": "",
"end-date-time": "",
"completion-percentage": 0,
"stop-at-stage": 3,
"result": "inprogress",
"timeout": 182,
"reason": "",
"inprogress": true,
"total-stages": 3,
"stages": [
{
"stage-id": 0,
"stage-name": "system-config-update-query",
"total-steps": 3,
"inprogress": true,
"start-date-time": "",
"end-date-time": "",
"reason": "",
"current-step": 0,
"result": "inprogress",
"timeout": 181,
"steps": [
{
"step-id": 0,
"step-name": "query-alarms",
"entity-type": "",
"entity-names": [],
"entity-uuids": [],
"start-date-time": "",
"end-date-time": "",
"timeout": 60,
"result": "success",
"reason": ""
},
{
"step-id": 1,
"step-name": "query-strategy-required",
"entity-type": "",
"entity-names": [],
"entity-uuids": [],
"start-date-time": "",
"end-date-time": "",
"timeout": 60,
"result": "success",
"reason": ""
},
{
"step-id": 2,
"step-name": "query-in-sync",
"entity-type": "",
"entity-names": [],
"entity-uuids": [],
"start-date-time": "",
"end-date-time": "",
"timeout": 60,
"result": "success",
"reason": ""
}
],
}
],
},
"apply-phase": {
"start-date-time": "",
"end-date-time": "",
"phase-name": "apply",
"completion-percentage": 100,
"total-stages": 0,
"stop-at-stage": 0,
"result": "initial",
"timeout": 0,
"reason": "",
"inprogress": false,
"stages": [],
"current-stage": 0
},
"abort-phase": {
"start-date-time": "",
"end-date-time": "",
"phase-name": "abort",
"completion-percentage": 100,
"total-stages": 0,
"stop-at-stage": 0,
"result": "initial",
"timeout": 0,
"reason": "",
"inprogress": false,
"stages": [],
"current-stage": 0
}
}
}

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2016-2021 Wind River Systems, Inc.
# Copyright (c) 2016-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -279,6 +279,9 @@ def create_strategy(token_id,
# required: 'to_version' passed to strategy as 'to-version'
api_cmd_payload['to-version'] = kwargs['to_version']
api_cmd_payload['default-instance-action'] = default_instance_action
elif 'system-config-update' == strategy_name:
api_cmd_payload['controller-apply-type'] = controller_apply_type
api_cmd_payload['default-instance-action'] = default_instance_action
elif 'sw-upgrade' == strategy_name:
# for upgrade: default-instance-action is hardcoded to MIGRATE
if 'start_upgrade' in kwargs and kwargs['start_upgrade']:

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2016-2021 Wind River Systems, Inc.
# Copyright (c) 2016-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -56,6 +56,9 @@ def get_extra_create_args(cmd_area, args):
elif 'fw-update-strategy' == cmd_area:
# no additional kwargs for firmware update
return {}
elif 'system-config-update-strategy' == cmd_area:
# no additional kwargs for system config update
return {}
elif 'kube-rootca-update-strategy' == cmd_area:
# kube rootca update supports expiry_date, subject and cert_file
return {
@ -384,6 +387,48 @@ def setup_patch_parser(commands):
_ = setup_show_cmd(sub_cmds)
def setup_system_config_update_parser(commands):
"""System config update Strategy Commands"""
cmd_area = 'system-config-update-strategy'
register_strategy(cmd_area, sw_update.STRATEGY_NAME_SYSTEM_CONFIG_UPDATE)
cmd_parser = commands.add_parser(cmd_area,
help='system config update Strategy')
cmd_parser.set_defaults(cmd_area=cmd_area)
sub_cmds = cmd_parser.add_subparsers(title='Sytem Config Update Commands',
metavar='')
sub_cmds.required = True
# define the create command
# alarm restrictions, defaults to strict
_ = setup_create_cmd(
sub_cmds,
[sw_update.APPLY_TYPE_SERIAL, # controller supports serial only
sw_update.APPLY_TYPE_IGNORE],
[sw_update.APPLY_TYPE_SERIAL, # storage supports serial only
sw_update.APPLY_TYPE_IGNORE],
[sw_update.APPLY_TYPE_SERIAL, # worker supports serial and parallel
sw_update.APPLY_TYPE_PARALLEL,
sw_update.APPLY_TYPE_IGNORE],
[sw_update.INSTANCE_ACTION_STOP_START, # instance actions
sw_update.INSTANCE_ACTION_MIGRATE],
[sw_update.ALARM_RESTRICTIONS_STRICT, # alarm restrictions
sw_update.ALARM_RESTRICTIONS_RELAXED],
min_parallel=2,
max_parallel=100 # config update supports 2..100 workers in parallel
)
# define the delete command
_ = setup_delete_cmd(sub_cmds)
# define the apply command
_ = setup_apply_cmd(sub_cmds)
# define the abort command
_ = setup_abort_cmd(sub_cmds)
# define the show command
_ = setup_show_cmd(sub_cmds)
def setup_upgrade_parser(commands):
"""Upgrade Strategy Commands"""
@ -468,6 +513,9 @@ def process_main(argv=sys.argv[1:]): # pylint: disable=dangerous-default-value
# Add software patch strategy commands
setup_patch_parser(commands)
# Add system config update strategy commands
setup_system_config_update_parser(commands)
# Add software upgrade strategy commands
setup_upgrade_parser(commands)

View File

@ -1,4 +1,4 @@
# Copyright (c) 2016-2021 Wind River Systems, Inc.
# Copyright (c) 2016-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -19,3 +19,4 @@ from nfv_client.sw_update._sw_update import STRATEGY_NAME_KUBE_ROOTCA_UPDATE #
from nfv_client.sw_update._sw_update import STRATEGY_NAME_KUBE_UPGRADE # noqa: F401
from nfv_client.sw_update._sw_update import STRATEGY_NAME_SW_PATCH # noqa: F401
from nfv_client.sw_update._sw_update import STRATEGY_NAME_SW_UPGRADE # noqa: F401
from nfv_client.sw_update._sw_update import STRATEGY_NAME_SYSTEM_CONFIG_UPDATE # noqa: F401

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2016-2022 Wind River Systems, Inc.
# Copyright (c) 2016-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -11,6 +11,7 @@ STRATEGY_NAME_SW_UPGRADE = 'sw-upgrade'
STRATEGY_NAME_FW_UPDATE = 'fw-update'
STRATEGY_NAME_KUBE_ROOTCA_UPDATE = 'kube-rootca-update'
STRATEGY_NAME_KUBE_UPGRADE = 'kube-upgrade'
STRATEGY_NAME_SYSTEM_CONFIG_UPDATE = 'system-config-update'
APPLY_TYPE_SERIAL = 'serial'
APPLY_TYPE_PARALLEL = 'parallel'
@ -130,6 +131,8 @@ def _display_strategy(strategy, details=False, active=False):
print("Strategy Kubernetes RootCA Update Strategy:")
elif strategy.name == STRATEGY_NAME_KUBE_UPGRADE:
print("Strategy Kubernetes Upgrade Strategy:")
elif strategy.name == STRATEGY_NAME_SYSTEM_CONFIG_UPDATE:
print("Strategy System Config Upgrade Strategy:")
else:
print("Strategy Unknown Strategy:")

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2016-2021 Wind River Systems, Inc.
# Copyright (c) 2016-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -24,6 +24,7 @@ function _swmanager()
fw-update-strategy
kube-rootca-update-strategy
kube-upgrade-strategy
system-config-update-strategy
"
if [ $COMP_CWORD -gt 1 ]; then
@ -252,6 +253,83 @@ function _swmanager()
esac
fi
# Provide actions for completion
COMPREPLY=($(compgen -W "${actions}" -- ${cur}))
return 0
;;
system-config-update-strategy)
local actions="
create
delete
apply
abort
show
"
if [ $COMP_CWORD -gt 2 ]; then
local action=${COMP_WORDS[2]}
#
# Complete the arguments for each action
#
case "$action" in
create)
local createopts="
--controller-apply-type
--storage-apply-type
--worker-apply-type
--max-parallel-worker-hosts
--instance-action
--alarm-restrictions
"
local createopt=${prev}
case "$createopt" in
--controller-apply-type|--storage-apply-type)
COMPREPLY=($(compgen -W "serial ignore" -- ${cur}))
return 0
;;
--worker-apply-type)
COMPREPLY=($(compgen -W "serial parallel ignore" -- ${cur}))
return 0
;;
--max-parallel-worker-hosts)
COMPREPLY=( $(compgen -- ${cur}))
return 0
;;
--instance-action)
COMPREPLY=($(compgen -W "migrate stop-start" -- ${cur}))
return 0
;;
--alarm-restrictions)
COMPREPLY=($(compgen -W "strict relaxed" -- ${cur}))
return 0
;;
*)
;;
esac
COMPREPLY=($(compgen -W "${createopts}" -- ${cur}))
return 0
;;
apply|abort)
if [ "${prev}" = "${action}" ]; then
COMPREPLY=($(compgen -W "--stage-id" -- ${cur}))
fi
return 0
;;
show)
if [ "${prev}" = "${action}" ]; then
COMPREPLY=($(compgen -W "--details --active" -- ${cur}))
fi
return 0
;;
delete)
# These subcommands have no options/arguments
COMPREPLY=( $(compgen -- ${cur}) )
return 0
;;
*)
;;
esac
fi
# Provide actions for completion
COMPREPLY=($(compgen -W "${actions}" -- ${cur}))
return 0

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015-2021 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -50,6 +50,9 @@ class _AlarmType(Constants):
KUBE_UPGRADE_AUTO_APPLY_INPROGRESS = Constant('kube-upgrade-auto-apply-inprogress')
KUBE_UPGRADE_AUTO_APPLY_ABORTING = Constant('kube-upgrade-auto-apply-aborting')
KUBE_UPGRADE_AUTO_APPLY_FAILED = Constant('kube-upgrade-auto-apply-failed')
SYSTEM_CONFIG_UPDATE_AUTO_APPLY_INPROGRESS = Constant('system-config-update-auto-apply-inprogress')
SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORTING = Constant('system-config-update-auto-apply-aborting')
SYSTEM_CONFIG_UPDATE_AUTO_APPLY_FAILED = Constant('system-config-update-auto-apply-failed')
@six.add_metaclass(Singleton)

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015-2021 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -196,6 +196,18 @@ class _EventId(Constants):
KUBE_UPGRADE_AUTO_APPLY_ABORT_FAILED = Constant('kube-upgrade-auto-apply-abort-failed')
KUBE_UPGRADE_AUTO_APPLY_ABORTED = Constant('kube-upgrade-auto-apply-aborted')
SYSTEM_CONFIG_UPDATE_AUTO_APPLY_START = Constant('system-config-update-auto-apply-started')
SYSTEM_CONFIG_UPDATE_AUTO_APPLY_INPROGRESS = Constant('system-config-update-auto-apply-inprogress')
SYSTEM_CONFIG_UPDATE_AUTO_APPLY_REJECTED = Constant('system-config-update-auto-apply-rejected')
SYSTEM_CONFIG_UPDATE_AUTO_APPLY_CANCELLED = Constant('system-config-update-auto-apply-cancelled')
SYSTEM_CONFIG_UPDATE_AUTO_APPLY_FAILED = Constant('system-config-update-auto-apply-failed')
SYSTEM_CONFIG_UPDATE_AUTO_APPLY_COMPLETED = Constant('system-config-update-auto-apply-completed')
SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORT = Constant('system-config-update-auto-apply-abort')
SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORTING = Constant('system-config-update-auto-apply-aborting')
SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORT_REJECTED = Constant('system-config-update-auto-apply-abort-rejected')
SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORT_FAILED = Constant('system-config-update-auto-apply-abort-failed')
SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORTED = Constant('system-config-update-auto-apply-aborted')
@six.add_metaclass(Singleton)
class _EventType(Constants):

View File

@ -97,6 +97,18 @@ _fm_kube_rootca_update_alarm_id_mapping = dict([
# Merge the kube rootca update mapping with the entire mapping
_fm_alarm_id_mapping.update(_fm_kube_rootca_update_alarm_id_mapping)
_fm_system_config_update_alarm_id_mapping = dict([
(alarm_objects_v1.ALARM_TYPE.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_INPROGRESS,
fm_constants.FM_ALARM_ID_SYSTEM_CONFIG_UPDATE_AUTO_APPLY_INPROGRESS),
(alarm_objects_v1.ALARM_TYPE.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORTING,
fm_constants.FM_ALARM_ID_SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORTING),
(alarm_objects_v1.ALARM_TYPE.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_FAILED,
fm_constants.FM_ALARM_ID_SYSTEM_CONFIG_UPDATE_AUTO_APPLY_FAILED),
])
# Merge the system config update mapping with the entire mapping
_fm_alarm_id_mapping.update(_fm_system_config_update_alarm_id_mapping)
_fm_alarm_type_mapping = dict([
(alarm_objects_v1.ALARM_EVENT_TYPE.COMMUNICATIONS_ALARM,
fm_constants.FM_ALARM_TYPE_1),

View File

@ -386,6 +386,35 @@ _fm_kube_rootca_update_event_id_mapping = dict([
# Merge the kube rootca update mapping with the entire mapping
_fm_event_id_mapping.update(_fm_kube_rootca_update_event_id_mapping)
# define system config update event mapping
_fm_system_config_update_event_id_mapping = dict([
(event_log_objects_v1.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_START,
fm_constants.FM_LOG_ID_SYSTEM_CONFIG_UPDATE_AUTO_APPLY_START),
(event_log_objects_v1.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_INPROGRESS,
fm_constants.FM_LOG_ID_SYSTEM_CONFIG_UPDATE_AUTO_APPLY_INPROGRESS),
(event_log_objects_v1.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_REJECTED,
fm_constants.FM_LOG_ID_SYSTEM_CONFIG_UPDATE_AUTO_APPLY_REJECTED),
(event_log_objects_v1.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_CANCELLED,
fm_constants.FM_LOG_ID_SYSTEM_CONFIG_UPDATE_AUTO_APPLY_CANCELLED),
(event_log_objects_v1.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_FAILED,
fm_constants.FM_LOG_ID_SYSTEM_CONFIG_UPDATE_AUTO_APPLY_FAILED),
(event_log_objects_v1.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_COMPLETED,
fm_constants.FM_LOG_ID_SYSTEM_CONFIG_UPDATE_AUTO_APPLY_COMPLETED),
(event_log_objects_v1.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORT,
fm_constants.FM_LOG_ID_SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORT),
(event_log_objects_v1.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORTING,
fm_constants.FM_LOG_ID_SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORTING),
(event_log_objects_v1.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORT_REJECTED,
fm_constants.FM_LOG_ID_SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORT_REJECTED),
(event_log_objects_v1.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORT_FAILED,
fm_constants.FM_LOG_ID_SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORT_FAILED),
(event_log_objects_v1.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORTED,
fm_constants.FM_LOG_ID_SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORTED),
])
# Merge the system config update mapping with the entire mapping
_fm_event_id_mapping.update(_fm_system_config_update_event_id_mapping)
_fm_event_type_mapping = dict([
(event_log_objects_v1.EVENT_TYPE.STATE_EVENT,
fm_constants.FM_ALARM_TYPE_4),

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2018-2022 Wind River Systems, Inc.
# Copyright (c) 2018-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -55,6 +55,28 @@ def get_client():
return kubernetes.client.CoreV1Api()
def get_kubertnetes_https_client():
"""
Get Kubernetes client with HTTPS enabled
"""
kubernetes.config.load_kube_config('/etc/kubernetes/admin.conf')
if K8S_MODULE_MAJOR_VERSION < 12:
c = kubernetes.client.Configuration()
else:
c = kubernetes.client.Configuration().get_default_copy()
kubernetes.client.Configuration.set_default(c)
return kubernetes.client
def get_customobjects_api_instance():
"""
Get a custom objects API instance
"""
client = get_kubertnetes_https_client()
return client.CustomObjectsApi()
def taint_node(node_name, effect, key, value):
"""
Apply a taint to a node
@ -231,3 +253,132 @@ def get_terminating_pods(node_name):
terminating_pods.append(pod.metadata.name)
return Result(','.join(terminating_pods))
def get_namespaced_custom_object(name, plural, group, version, namespace):
"""
Get a custom resource object in a namespace
"""
# Get a CustomObjectsApi instance
api_instance = get_customobjects_api_instance()
try:
resource = api_instance.get_namespaced_custom_object(
group=group,
version=version,
name=name,
namespace=namespace,
plural=plural
)
return Result(resource)
except ApiException as e:
DLOG.exception(
"Failed to get object %s from namespace %s, "
"reason: %s" % (name, namespace, e.reason))
return None
def get_deployment_host(name):
"""
Get a host in the deployment namespace
"""
# Get a CustomObjectsApi instance
api_instance = get_customobjects_api_instance()
try:
resource = api_instance.get_namespaced_custom_object(
group='starlingx.windriver.com',
version='v1',
name=name,
namespace='deployment',
plural='hosts'
)
unlock_request = resource.get('status').get('strategyRequired')
result = {'name': name, 'unlock_request': unlock_request}
return Result(result)
except ApiException as e:
DLOG.exception(
"Failed to get object %s from namespace deployment, "
"reason: %s" % (name, e.reason))
return None
def list_namespaced_custom_objects(plural, group, version, namespace):
"""
List custom resource objects in a namespace
"""
# Get a CustomObjectsApi instance
api_instance = get_customobjects_api_instance()
try:
resources = api_instance.list_namespaced_custom_object(
group=group,
version=version,
namespace=namespace,
plural=plural
)
return Result(resources)
except ApiException as e:
DLOG.exception(
"Failed to list objects %s from namespace %s, "
"reason: %s" % (plural, namespace, e.reason))
return None
def list_deployment_hosts():
"""
List hosts in a deployment namespace
"""
# Get a CustomObjectsApi instance
api_instance = get_customobjects_api_instance()
try:
resources = api_instance.list_namespaced_custom_object(
group='starlingx.windriver.com',
version='v1',
namespace='deployment',
plural='hosts'
)
if not resources:
return None
results = list()
for resource in resources.get('items'):
name = resource.get('metadata').get('name')
unlock_request = resource.get('status').get('strategyRequired')
results.append({'name': name,
'unlock_request': unlock_request})
return Result(results)
except ApiException as e:
DLOG.exception(
"Failed to list hosts from deployment namespace, "
"reason: %s" % e.reason)
return None
def get_namespaced_running_pods(namespace, name):
"""
Get running pods in a namespace
"""
api_instance = get_client()
try:
response = api_instance.list_namespaced_pod(
namespace=namespace,
field_selector="status.phase=Running",)
except ApiException as e:
DLOG.exception(
"Failed to list pods from namespace %s, "
"reason: %s" % (namespace, e.reason))
return None
pods = response.items
found = list()
if pods is not None:
for pod in pods:
if name in pod.metadata.name:
found.append(pod.metadata.name)
return Result(','.join(found))

View File

@ -3806,6 +3806,118 @@ class NFVIInfrastructureAPI(nfvi.api.v1.NFVIInfrastructureAPI):
callback.send(response)
callback.close()
def get_deployment_host(self, future, host_name, callback):
"""
Get a host resource from the deployment namespace space
"""
response = dict()
response['completed'] = False
response['reason'] = ''
try:
future.set_timeouts(config.CONF.get('nfvi-timeouts', None))
future.work(kubernetes_client.get_deployment_host, host_name)
future.result = (yield)
if not future.result.is_complete():
DLOG.error("Kubernetes get_deployment_host failed, operation "
"did not complete, host_name=%s" % host_name)
self.set_response_error(response, "Kubernetes get-deployment-host")
return
response['result-data'] = future.result.data
response['completed'] = True
except Exception as e:
DLOG.exception("Caught exception while trying to get "
"deployment hosts: %s, error=%s." % (host_name, e))
finally:
callback.send(response)
callback.close()
def list_deployment_hosts(self, future, callback):
"""
List a hosts resource from the deployment namespace space
"""
response = dict()
response['completed'] = False
response['reason'] = ''
try:
future.set_timeouts(config.CONF.get('nfvi-timeouts', None))
future.work(kubernetes_client.list_deployment_hosts)
future.result = (yield)
if not future.result.is_complete() or future.result.data is None:
DLOG.error("Kubernetes list_deployment_hosts failed, operation "
"did not complete.")
self.set_response_error(response, "Kubernetes list-deployment-hosts")
return
hosts = list()
for host_data in future.result.data:
host = nfvi.objects.v1.HostSystemConfigUpdate(
host_data['name'], host_data['unlock_request'])
hosts.append(host)
response['result-data'] = hosts
response['completed'] = True
except Exception as e:
DLOG.exception("Caught exception while trying to list "
"deployment hosts, error=%s." % (e))
finally:
callback.send(response)
callback.close()
def get_system_config_unlock_request(self, future, host_names, callback):
"""
Get unlock request from host resource status
"""
response = dict()
response['completed'] = False
response['reason'] = ''
try:
future.set_timeouts(config.CONF.get('nfvi-timeouts', None))
result = list()
for host_name in host_names:
future.work(kubernetes_client.get_deployment_host, host_name)
future.result = (yield)
if not future.result.is_complete():
DLOG.error("Cannot get resource of host: %s from deployment "
"namespace." % host_name)
self.set_response_error(response, "Kubernetes get-deployment-host")
return
if future.result.data['unlock_request'] != 'unlock_required':
# The host is not ready for unlock, do not update the reason
# as the the transitional status is expected.
DLOG.debug("Host: %s is not ready for unlock." % host_name)
return
host_resource = nfvi.objects.v1.HostSystemConfigUpdate(
future.result.data['name'],
future.result.data['unlock_request']
)
result.append(host_resource)
response['completed'] = True
response['result-data'] = result
except Exception as e:
DLOG.exception("Caught exception while trying to check the unlock "
"requst from kubernetes deployment namespace %s, "
"error=%s." % (host_name, e))
finally:
callback.send(response)
callback.close()
def sw_update_rest_api_get_handler(self, request_dispatch):
"""
Software update Rest-API GET handler callback

View File

@ -282,3 +282,10 @@ class TestCLIKubeUpgradeStrategy(TestNFVClientShell,
def required_create_fields(self):
"""Kube Upgrade requires a to-version for create"""
return ['--to-version=1.2.3']
class TestSystemConfigUpdateStrategy(TestNFVClientShell,
StrategyMixin):
def setUp(self):
super(TestSystemConfigUpdateStrategy, self).setUp()
self.set_strategy('system-config-update-strategy')

View File

@ -434,3 +434,67 @@ class TestNFVPluginsK8SGetTerminatingPods(testcase.NFVTestCase):
assert result.result_data == \
'test-pod-terminating,test-pod-terminating-2'
@mock.patch('kubernetes.config.load_kube_config', mock_load_kube_config)
class TestNFVPluginsK8SGetNamespacedRunningPods(testcase.NFVTestCase):
list_namespaced_pod_result = kubernetes.client.V1PodList(
api_version="v1",
items=[
kubernetes.client.V1Pod(
api_version="v1",
kind="Pod",
metadata=kubernetes.client.V1ObjectMeta(
name="test-pod-not-found-1",
namespace="test-namespace-1"),
),
kubernetes.client.V1Pod(
api_version="v1",
kind="Pod",
metadata=kubernetes.client.V1ObjectMeta(
name="test-pod-not-found-2",
namespace="test-namespace-1"),
),
kubernetes.client.V1Pod(
api_version="v1",
kind="Pod",
metadata=kubernetes.client.V1ObjectMeta(
name="test-pod-found-1",
namespace="test-namespace-1"),
),
kubernetes.client.V1Pod(
api_version="v1",
kind="Pod",
metadata=kubernetes.client.V1ObjectMeta(
name="test-pod-found-2",
namespace="test-namespace-1"),
),
]
)
def setUp(self):
super(TestNFVPluginsK8SGetNamespacedRunningPods, self).setUp()
def mock_list_namespaced_pod(obj, namespace, field_selector=""):
return self.list_namespaced_pod_result
self.mocked_list_namespaced_pod = mock.patch(
'kubernetes.client.CoreV1Api.list_namespaced_pod',
mock_list_namespaced_pod)
self.mocked_list_namespaced_pod.start()
def tearDown(self):
super(TestNFVPluginsK8SGetNamespacedRunningPods, self).tearDown()
self.mocked_list_namespaced_pod.stop()
def test_get_terminating_with_two_terminating(self):
result = kubernetes_client.get_namespaced_running_pods(
namespace="test-namespace-1",
name="test-pod-found"
)
assert result.result_data == \
'test-pod-found-1,test-pod-found-2'

View File

@ -0,0 +1,790 @@
#
# Copyright (c) 2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
from unittest import mock
import uuid
from nfv_common import strategy as common_strategy
from nfv_vim import nfvi
from nfv_vim.objects import SW_UPDATE_ALARM_RESTRICTION
from nfv_vim.objects import SW_UPDATE_APPLY_TYPE
from nfv_vim.objects import SW_UPDATE_INSTANCE_ACTION
from nfv_vim.objects import SystemConfigUpdate
from nfv_vim.strategy._strategy import SystemConfigUpdateStrategy
from nfv_unit_tests.tests import sw_update_testcase
@mock.patch('nfv_vim.event_log._instance._event_issue',
sw_update_testcase.fake_event_issue)
@mock.patch('nfv_vim.objects._sw_update.SwUpdate.save',
sw_update_testcase.fake_save)
@mock.patch('nfv_vim.objects._sw_update.timers.timers_create_timer',
sw_update_testcase.fake_timer)
@mock.patch('nfv_vim.nfvi.nfvi_compute_plugin_disabled',
sw_update_testcase.fake_nfvi_compute_plugin_disabled)
class TestSystemConfigUpdateStrategy(sw_update_testcase.SwUpdateStrategyTestCase):
def _create_system_config_update_strategy(self,
sw_update_obj,
controller_apply_type=SW_UPDATE_APPLY_TYPE.SERIAL,
storage_apply_type=SW_UPDATE_APPLY_TYPE.SERIAL,
worker_apply_type=SW_UPDATE_APPLY_TYPE.SERIAL,
max_parallel_worker_hosts=10,
default_instance_action=SW_UPDATE_INSTANCE_ACTION.STOP_START,
alarm_restrictions=SW_UPDATE_ALARM_RESTRICTION.STRICT,
single_controller=False,
nfvi_system_config_update_hosts=None):
"""
Create a system config update strategy
"""
strategy = SystemConfigUpdateStrategy(
uuid=str(uuid.uuid4()),
controller_apply_type=controller_apply_type,
storage_apply_type=storage_apply_type,
worker_apply_type=worker_apply_type,
max_parallel_worker_hosts=max_parallel_worker_hosts,
default_instance_action=default_instance_action,
alarm_restrictions=alarm_restrictions,
single_controller=single_controller,
ignore_alarms=[])
strategy.sw_update_obj = sw_update_obj
strategy.nfvi_system_config_update_hosts = nfvi_system_config_update_hosts
return strategy
@mock.patch('nfv_common.strategy._strategy.Strategy._build')
def test_system_config_update_strategy_build_steps(self, fake_build):
"""
Verify build phases, etc.. for system config update strategy creation.
"""
# setup a minimal host environment
self.create_host('controller-0', aio=True)
# construct the strategy. the update_obj MUST be declared here and not
# in the create method, because it is a weakref and will be cleaned up
# when it goes out of scope.
update_obj = SystemConfigUpdate()
strategy = self._create_system_config_update_strategy(update_obj)
# The 'build' constructs a strategy that includes multiple queries
# the results of those queries are not used until build_complete
# mock away '_build', which invokes the build steps and their api calls
fake_build.return_value = None
strategy.build()
# verify the build phase and steps
build_phase = strategy.build_phase.as_dict()
query_steps = [
{'name': 'query-alarms'},
{'name': 'query-system-config-update-hosts'},
]
expected_results = {
'total_stages': 1,
'stages': [
{'name': 'system-config-update-query',
'total_steps': len(query_steps),
'steps': query_steps,
},
],
}
sw_update_testcase.validate_phase(build_phase, expected_results)
def temp_log(self, txt):
with open('./tbd.txt', 'a') as f:
f.write(txt + "\n")
@mock.patch('nfv_common.strategy._strategy.Strategy._build')
def test_apply_system_config_update_strategy_simplex(self, fake_build):
self.create_host('controller-0', aio=True)
update_obj = SystemConfigUpdate()
nfvi_system_config_update_hosts = list()
controller_0_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'controller-0', 'lock_required')
nfvi_system_config_update_hosts.append(controller_0_resource)
strategy = self._create_system_config_update_strategy(
update_obj,
single_controller=True,
nfvi_system_config_update_hosts=nfvi_system_config_update_hosts)
strategy.build_complete(common_strategy.STRATEGY_RESULT.SUCCESS, "")
self.assertFalse(strategy.is_build_failed())
self.assertEqual(strategy.build_phase.result_reason, "")
apply_phase = strategy.apply_phase.as_dict()
expected_results = {
'total_stages': 1,
'stages': [
{
'name': "system-config-update-worker-hosts",
'total_steps': 6,
'steps': [
{'name': 'query-alarms'},
{'name': 'lock-hosts',
'entity_names': ['controller-0']},
{'name': 'system-config-update-hosts',
'entity_names': ['controller-0']},
{'name': 'system-stabilize',
'timeout': 15},
{'name': 'unlock-hosts',
'entity_names': ['controller-0']},
{'name': 'wait-alarms-clear',
'timeout': 1800},
]
},
]
}
sw_update_testcase.validate_strategy_persists(strategy)
sw_update_testcase.validate_phase(apply_phase, expected_results)
@mock.patch('nfv_common.strategy._strategy.Strategy._build')
def test_apply_system_config_update_strategy_duplex(self, fake_build):
self.create_host('controller-0', aio=True)
self.create_host('controller-1', aio=True)
update_obj = SystemConfigUpdate()
nfvi_system_config_update_hosts = list()
controller_0_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'controller-0', 'lock_required')
controller_1_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'controller-1', 'lock_required')
nfvi_system_config_update_hosts.append(controller_0_resource)
nfvi_system_config_update_hosts.append(controller_1_resource)
strategy = self._create_system_config_update_strategy(
update_obj,
nfvi_system_config_update_hosts=nfvi_system_config_update_hosts)
strategy.build_complete(common_strategy.STRATEGY_RESULT.SUCCESS, "")
self.assertFalse(strategy.is_build_failed())
self.assertEqual(strategy.build_phase.result_reason, "")
apply_phase = strategy.apply_phase.as_dict()
expected_results = {
'total_stages': 2,
'stages': [
{
'name': "system-config-update-worker-hosts",
'total_steps': 7,
'steps': [
{'name': 'query-alarms'},
{'name': 'swact-hosts',
'entity_names': ['controller-0']},
{'name': 'lock-hosts',
'entity_names': ['controller-0']},
{'name': 'system-config-update-hosts',
'entity_names': ['controller-0']},
{'name': 'system-stabilize',
'timeout': 15},
{'name': 'unlock-hosts',
'entity_names': ['controller-0']},
{'name': 'wait-alarms-clear',
'timeout': 1800},
]
},
{
'name': "system-config-update-worker-hosts",
'total_steps': 7,
'steps': [
{'name': 'query-alarms'},
{'name': 'swact-hosts',
'entity_names': ['controller-1']},
{'name': 'lock-hosts',
'entity_names': ['controller-1']},
{'name': 'system-config-update-hosts',
'entity_names': ['controller-1']},
{'name': 'system-stabilize',
'timeout': 15},
{'name': 'unlock-hosts',
'entity_names': ['controller-1']},
{'name': 'wait-alarms-clear',
'timeout': 1800},
]
},
]
}
sw_update_testcase.validate_strategy_persists(strategy)
sw_update_testcase.validate_phase(apply_phase, expected_results)
@mock.patch('nfv_common.strategy._strategy.Strategy._build')
def test_apply_system_config_update_strategy_standard_serial(self, fake_build):
self.create_host('controller-0')
self.create_host('controller-1')
self.create_host('storage-0')
self.create_host('storage-1')
self.create_host('compute-0')
self.create_host('compute-1')
update_obj = SystemConfigUpdate()
nfvi_system_config_update_hosts = list()
controller_0_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'controller-0', 'lock_required')
controller_1_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'controller-1', 'lock_required')
compute_0_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'compute-0', 'lock_required')
compute_1_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'compute-1', 'lock_required')
storage_0_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'storage-0', 'lock_required')
storage_1_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'storage-1', 'lock_required')
nfvi_system_config_update_hosts.append(controller_0_resource)
nfvi_system_config_update_hosts.append(controller_1_resource)
nfvi_system_config_update_hosts.append(compute_0_resource)
nfvi_system_config_update_hosts.append(compute_1_resource)
nfvi_system_config_update_hosts.append(storage_0_resource)
nfvi_system_config_update_hosts.append(storage_1_resource)
strategy = self._create_system_config_update_strategy(
update_obj,
nfvi_system_config_update_hosts=nfvi_system_config_update_hosts)
strategy.build_complete(common_strategy.STRATEGY_RESULT.SUCCESS, "")
self.assertFalse(strategy.is_build_failed())
self.assertEqual(strategy.build_phase.result_reason, "")
apply_phase = strategy.apply_phase.as_dict()
expected_results = {
'total_stages': 6,
'stages': [
{
'name': "system-config-update-controllers",
'total_steps': 7,
'steps': [
{'name': 'query-alarms'},
{'name': 'swact-hosts',
'entity_names': ['controller-0']},
{'name': 'lock-hosts',
'entity_names': ['controller-0']},
{'name': 'system-config-update-hosts',
'entity_names': ['controller-0']},
{'name': 'system-stabilize',
'timeout': 15},
{'name': 'unlock-hosts',
'entity_names': ['controller-0']},
{'name': 'wait-alarms-clear',
'timeout': 1800},
]
},
{
'name': "system-config-update-controllers",
'total_steps': 7,
'steps': [
{'name': 'query-alarms'},
{'name': 'swact-hosts',
'entity_names': ['controller-1']},
{'name': 'lock-hosts',
'entity_names': ['controller-1']},
{'name': 'system-config-update-hosts',
'entity_names': ['controller-1']},
{'name': 'system-stabilize',
'timeout': 15},
{'name': 'unlock-hosts',
'entity_names': ['controller-1']},
{'name': 'wait-alarms-clear',
'timeout': 1800},
]
},
{
'name': "system-config-update-storage-hosts",
'total_steps': 6,
'steps': [
{'name': 'query-alarms'},
{'name': 'lock-hosts',
'entity_names': ['storage-0']},
{'name': 'system-config-update-hosts',
'entity_names': ['storage-0']},
{'name': 'system-stabilize',
'timeout': 15},
{'name': 'unlock-hosts',
'entity_names': ['storage-0']},
{'name': 'wait-data-sync',
'timeout': 1800},
]
},
{
'name': "system-config-update-storage-hosts",
'total_steps': 6,
'steps': [
{'name': 'query-alarms'},
{'name': 'lock-hosts',
'entity_names': ['storage-1']},
{'name': 'system-config-update-hosts',
'entity_names': ['storage-1']},
{'name': 'system-stabilize',
'timeout': 15},
{'name': 'unlock-hosts',
'entity_names': ['storage-1']},
{'name': 'wait-data-sync',
'timeout': 1800},
]
},
{
'name': "system-config-update-worker-hosts",
'total_steps': 6,
'steps': [
{'name': 'query-alarms'},
{'name': 'lock-hosts',
'entity_names': ['compute-0']},
{'name': 'system-config-update-hosts',
'entity_names': ['compute-0']},
{'name': 'system-stabilize',
'timeout': 15},
{'name': 'unlock-hosts',
'entity_names': ['compute-0']},
{'name': 'wait-alarms-clear',
'timeout': 600},
]
},
{
'name': "system-config-update-worker-hosts",
'total_steps': 6,
'steps': [
{'name': 'query-alarms'},
{'name': 'lock-hosts',
'entity_names': ['compute-1']},
{'name': 'system-config-update-hosts',
'entity_names': ['compute-1']},
{'name': 'system-stabilize',
'timeout': 15},
{'name': 'unlock-hosts',
'entity_names': ['compute-1']},
{'name': 'wait-alarms-clear',
'timeout': 600},
]
},
]
}
sw_update_testcase.validate_strategy_persists(strategy)
sw_update_testcase.validate_phase(apply_phase, expected_results)
@mock.patch('nfv_common.strategy._strategy.Strategy._build')
def test_apply_system_config_update_strategy_standard_parallel_worker(self, fake_build):
self.create_host('controller-0')
self.create_host('controller-1')
self.create_host('storage-0')
self.create_host('storage-1')
self.create_host('compute-0')
self.create_host('compute-1')
update_obj = SystemConfigUpdate()
nfvi_system_config_update_hosts = list()
controller_0_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'controller-0', 'lock_required')
controller_1_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'controller-1', 'lock_required')
compute_0_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'compute-0', 'lock_required')
compute_1_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'compute-1', 'lock_required')
storage_0_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'storage-0', 'lock_required')
storage_1_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'storage-1', 'lock_required')
nfvi_system_config_update_hosts.append(controller_0_resource)
nfvi_system_config_update_hosts.append(controller_1_resource)
nfvi_system_config_update_hosts.append(compute_0_resource)
nfvi_system_config_update_hosts.append(compute_1_resource)
nfvi_system_config_update_hosts.append(storage_0_resource)
nfvi_system_config_update_hosts.append(storage_1_resource)
strategy = self._create_system_config_update_strategy(
update_obj,
worker_apply_type=SW_UPDATE_APPLY_TYPE.PARALLEL,
nfvi_system_config_update_hosts=nfvi_system_config_update_hosts)
strategy.build_complete(common_strategy.STRATEGY_RESULT.SUCCESS, "")
self.assertFalse(strategy.is_build_failed())
self.assertEqual(strategy.build_phase.result_reason, "")
apply_phase = strategy.apply_phase.as_dict()
expected_results = {
'total_stages': 5,
'stages': [
{
'name': "system-config-update-controllers",
'total_steps': 7,
'steps': [
{'name': 'query-alarms'},
{'name': 'swact-hosts',
'entity_names': ['controller-0']},
{'name': 'lock-hosts',
'entity_names': ['controller-0']},
{'name': 'system-config-update-hosts',
'entity_names': ['controller-0']},
{'name': 'system-stabilize',
'timeout': 15},
{'name': 'unlock-hosts',
'entity_names': ['controller-0']},
{'name': 'wait-alarms-clear',
'timeout': 1800},
]
},
{
'name': "system-config-update-controllers",
'total_steps': 7,
'steps': [
{'name': 'query-alarms'},
{'name': 'swact-hosts',
'entity_names': ['controller-1']},
{'name': 'lock-hosts',
'entity_names': ['controller-1']},
{'name': 'system-config-update-hosts',
'entity_names': ['controller-1']},
{'name': 'system-stabilize',
'timeout': 15},
{'name': 'unlock-hosts',
'entity_names': ['controller-1']},
{'name': 'wait-alarms-clear',
'timeout': 1800},
]
},
{
'name': "system-config-update-storage-hosts",
'total_steps': 6,
'steps': [
{'name': 'query-alarms'},
{'name': 'lock-hosts',
'entity_names': ['storage-0']},
{'name': 'system-config-update-hosts',
'entity_names': ['storage-0']},
{'name': 'system-stabilize',
'timeout': 15},
{'name': 'unlock-hosts',
'entity_names': ['storage-0']},
{'name': 'wait-data-sync',
'timeout': 1800},
]
},
{
'name': "system-config-update-storage-hosts",
'total_steps': 6,
'steps': [
{'name': 'query-alarms'},
{'name': 'lock-hosts',
'entity_names': ['storage-1']},
{'name': 'system-config-update-hosts',
'entity_names': ['storage-1']},
{'name': 'system-stabilize',
'timeout': 15},
{'name': 'unlock-hosts',
'entity_names': ['storage-1']},
{'name': 'wait-data-sync',
'timeout': 1800},
]
},
{
'name': "system-config-update-worker-hosts",
'total_steps': 6,
'steps': [
{'name': 'query-alarms'},
{'name': 'lock-hosts',
'entity_names': ['compute-0', 'compute-1']},
{'name': 'system-config-update-hosts',
'entity_names': ['compute-0', 'compute-1']},
{'name': 'system-stabilize',
'timeout': 15},
{'name': 'unlock-hosts',
'entity_names': ['compute-0', 'compute-1']},
{'name': 'wait-alarms-clear',
'timeout': 600},
]
},
]
}
sw_update_testcase.validate_strategy_persists(strategy)
sw_update_testcase.validate_phase(apply_phase, expected_results)
@mock.patch('nfv_common.strategy._strategy.Strategy._build')
def test_apply_system_config_update_strategy_host_not_required(self, fake_build):
self.create_host('controller-0')
self.create_host('controller-1')
self.create_host('storage-0')
self.create_host('storage-1')
self.create_host('compute-0')
self.create_host('compute-1')
update_obj = SystemConfigUpdate()
nfvi_system_config_update_hosts = list()
controller_0_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'controller-0', 'lock_required')
controller_1_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'controller-1', 'not_required')
compute_0_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'compute-0', 'lock_required')
compute_1_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'compute-1', 'not_required')
storage_0_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'storage-0', 'not_required')
storage_1_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'storage-1', 'lock_required')
nfvi_system_config_update_hosts.append(controller_0_resource)
nfvi_system_config_update_hosts.append(controller_1_resource)
nfvi_system_config_update_hosts.append(compute_0_resource)
nfvi_system_config_update_hosts.append(compute_1_resource)
nfvi_system_config_update_hosts.append(storage_0_resource)
nfvi_system_config_update_hosts.append(storage_1_resource)
strategy = self._create_system_config_update_strategy(
update_obj,
worker_apply_type=SW_UPDATE_APPLY_TYPE.PARALLEL,
nfvi_system_config_update_hosts=nfvi_system_config_update_hosts)
strategy.build_complete(common_strategy.STRATEGY_RESULT.SUCCESS, "")
self.assertFalse(strategy.is_build_failed())
self.assertEqual(strategy.build_phase.result_reason, "")
apply_phase = strategy.apply_phase.as_dict()
expected_results = {
'total_stages': 3,
'stages': [
{
'name': "system-config-update-controllers",
'total_steps': 7,
'steps': [
{'name': 'query-alarms'},
{'name': 'swact-hosts',
'entity_names': ['controller-0']},
{'name': 'lock-hosts',
'entity_names': ['controller-0']},
{'name': 'system-config-update-hosts',
'entity_names': ['controller-0']},
{'name': 'system-stabilize',
'timeout': 15},
{'name': 'unlock-hosts',
'entity_names': ['controller-0']},
{'name': 'wait-alarms-clear',
'timeout': 1800},
]
},
{
'name': "system-config-update-storage-hosts",
'total_steps': 6,
'steps': [
{'name': 'query-alarms'},
{'name': 'lock-hosts',
'entity_names': ['storage-1']},
{'name': 'system-config-update-hosts',
'entity_names': ['storage-1']},
{'name': 'system-stabilize',
'timeout': 15},
{'name': 'unlock-hosts',
'entity_names': ['storage-1']},
{'name': 'wait-data-sync',
'timeout': 1800},
]
},
{
'name': "system-config-update-worker-hosts",
'total_steps': 6,
'steps': [
{'name': 'query-alarms'},
{'name': 'lock-hosts',
'entity_names': ['compute-0']},
{'name': 'system-config-update-hosts',
'entity_names': ['compute-0']},
{'name': 'system-stabilize',
'timeout': 15},
{'name': 'unlock-hosts',
'entity_names': ['compute-0']},
{'name': 'wait-alarms-clear',
'timeout': 600},
]
},
]
}
sw_update_testcase.validate_strategy_persists(strategy)
sw_update_testcase.validate_phase(apply_phase, expected_results)
@mock.patch('nfv_common.strategy._strategy.Strategy._build')
def test_apply_system_config_update_strategy_controller_ignore(self, fake_build):
self.create_host('controller-0')
self.create_host('controller-1')
self.create_host('storage-0')
self.create_host('storage-1')
self.create_host('compute-0')
self.create_host('compute-1')
update_obj = SystemConfigUpdate()
nfvi_system_config_update_hosts = list()
controller_0_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'controller-0', 'lock_required')
controller_1_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'controller-1', 'not_required')
compute_0_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'compute-0', 'lock_required')
compute_1_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'compute-1', 'not_required')
storage_0_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'storage-0', 'not_required')
storage_1_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'storage-1', 'lock_required')
nfvi_system_config_update_hosts.append(controller_0_resource)
nfvi_system_config_update_hosts.append(controller_1_resource)
nfvi_system_config_update_hosts.append(compute_0_resource)
nfvi_system_config_update_hosts.append(compute_1_resource)
nfvi_system_config_update_hosts.append(storage_0_resource)
nfvi_system_config_update_hosts.append(storage_1_resource)
strategy = self._create_system_config_update_strategy(
update_obj,
controller_apply_type=SW_UPDATE_APPLY_TYPE.IGNORE,
worker_apply_type=SW_UPDATE_APPLY_TYPE.PARALLEL,
nfvi_system_config_update_hosts=nfvi_system_config_update_hosts)
strategy.build_complete(common_strategy.STRATEGY_RESULT.SUCCESS, "")
self.assertFalse(strategy.is_build_failed())
self.assertEqual(strategy.build_phase.result_reason, "")
apply_phase = strategy.apply_phase.as_dict()
expected_results = {
'total_stages': 2,
'stages': [
{
'name': "system-config-update-storage-hosts",
'total_steps': 6,
'steps': [
{'name': 'query-alarms'},
{'name': 'lock-hosts',
'entity_names': ['storage-1']},
{'name': 'system-config-update-hosts',
'entity_names': ['storage-1']},
{'name': 'system-stabilize',
'timeout': 15},
{'name': 'unlock-hosts',
'entity_names': ['storage-1']},
{'name': 'wait-data-sync',
'timeout': 1800},
]
},
{
'name': "system-config-update-worker-hosts",
'total_steps': 6,
'steps': [
{'name': 'query-alarms'},
{'name': 'lock-hosts',
'entity_names': ['compute-0']},
{'name': 'system-config-update-hosts',
'entity_names': ['compute-0']},
{'name': 'system-stabilize',
'timeout': 15},
{'name': 'unlock-hosts',
'entity_names': ['compute-0']},
{'name': 'wait-alarms-clear',
'timeout': 600},
]
},
]
}
sw_update_testcase.validate_strategy_persists(strategy)
sw_update_testcase.validate_phase(apply_phase, expected_results)
@mock.patch('nfv_common.strategy._strategy.Strategy._build')
def test_apply_system_config_update_strategy_worker_ignore(self, fake_build):
self.create_host('controller-0')
self.create_host('controller-1')
self.create_host('storage-0')
self.create_host('storage-1')
self.create_host('compute-0')
self.create_host('compute-1')
update_obj = SystemConfigUpdate()
nfvi_system_config_update_hosts = list()
controller_0_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'controller-0', 'lock_required')
controller_1_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'controller-1', 'not_required')
compute_0_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'compute-0', 'lock_required')
compute_1_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'compute-1', 'not_required')
storage_0_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'storage-0', 'not_required')
storage_1_resource = nfvi.objects.v1.HostSystemConfigUpdate(
'storage-1', 'lock_required')
nfvi_system_config_update_hosts.append(controller_0_resource)
nfvi_system_config_update_hosts.append(controller_1_resource)
nfvi_system_config_update_hosts.append(compute_0_resource)
nfvi_system_config_update_hosts.append(compute_1_resource)
nfvi_system_config_update_hosts.append(storage_0_resource)
nfvi_system_config_update_hosts.append(storage_1_resource)
strategy = self._create_system_config_update_strategy(
update_obj,
worker_apply_type=SW_UPDATE_APPLY_TYPE.IGNORE,
nfvi_system_config_update_hosts=nfvi_system_config_update_hosts)
strategy.build_complete(common_strategy.STRATEGY_RESULT.SUCCESS, "")
self.assertFalse(strategy.is_build_failed())
self.assertEqual(strategy.build_phase.result_reason, "")
apply_phase = strategy.apply_phase.as_dict()
expected_results = {
'total_stages': 2,
'stages': [
{
'name': "system-config-update-controllers",
'total_steps': 7,
'steps': [
{'name': 'query-alarms'},
{'name': 'swact-hosts',
'entity_names': ['controller-0']},
{'name': 'lock-hosts',
'entity_names': ['controller-0']},
{'name': 'system-config-update-hosts',
'entity_names': ['controller-0']},
{'name': 'system-stabilize',
'timeout': 15},
{'name': 'unlock-hosts',
'entity_names': ['controller-0']},
{'name': 'wait-alarms-clear',
'timeout': 1800},
]
},
{
'name': "system-config-update-storage-hosts",
'total_steps': 6,
'steps': [
{'name': 'query-alarms'},
{'name': 'lock-hosts',
'entity_names': ['storage-1']},
{'name': 'system-config-update-hosts',
'entity_names': ['storage-1']},
{'name': 'system-stabilize',
'timeout': 15},
{'name': 'unlock-hosts',
'entity_names': ['storage-1']},
{'name': 'wait-data-sync',
'timeout': 1800},
]
},
]
}
sw_update_testcase.validate_strategy_persists(strategy)
sw_update_testcase.validate_phase(apply_phase, expected_results)

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2016-2021 Wind River Systems, Inc.
# Copyright (c) 2016-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -188,6 +188,42 @@ _alarm_templates = {
"problem persists contact next level of support"),
'exclude_alarm_context': [alarm.ALARM_CONTEXT.TENANT],
},
alarm.ALARM_TYPE.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_INPROGRESS: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'event_type': alarm.ALARM_EVENT_TYPE.EQUIPMENT_ALARM,
'severity': alarm.ALARM_SEVERITY.MAJOR,
'probable_cause': alarm.ALARM_PROBABLE_CAUSE.UNKNOWN,
'reason_text': "System config update auto-apply inprogress",
'repair_action': ("Wait for system config update auto-apply to "
"complete; if problem persists contact next "
"level of support"),
'exclude_alarm_context': [alarm.ALARM_CONTEXT.TENANT],
},
alarm.ALARM_TYPE.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORTING: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'event_type': alarm.ALARM_EVENT_TYPE.EQUIPMENT_ALARM,
'severity': alarm.ALARM_SEVERITY.MAJOR,
'probable_cause': alarm.ALARM_PROBABLE_CAUSE.UNKNOWN,
'reason_text': "System config update auto-apply aborting",
'repair_action': ("Wait for system config update auto-apply abort "
"to complete; if problem persists contact next "
"level of support"),
'exclude_alarm_context': [alarm.ALARM_CONTEXT.TENANT],
},
alarm.ALARM_TYPE.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_FAILED: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'event_type': alarm.ALARM_EVENT_TYPE.EQUIPMENT_ALARM,
'severity': alarm.ALARM_SEVERITY.CRITICAL,
'probable_cause': alarm.ALARM_PROBABLE_CAUSE.UNKNOWN,
'reason_text': "System config update auto-apply failed",
'repair_action': ("Attempt to apply system config update manually; "
"if problem persists contact next level of support"),
'exclude_alarm_context': [alarm.ALARM_CONTEXT.TENANT],
},
}

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2016-2022 Wind River Systems, Inc.
# Copyright (c) 2016-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -13,6 +13,7 @@ from nfv_vim.api.acl.policies import kube_upgrade_strategy_policy
from nfv_vim.api.acl.policies import sw_patch_strategy_policy
from nfv_vim.api.acl.policies import sw_update_strategy_policy
from nfv_vim.api.acl.policies import sw_upgrade_strategy_policy
from nfv_vim.api.acl.policies import system_config_update_strategy_policy
from nfv_vim.api.acl import policy
from nfv_vim.api import openstack
@ -46,7 +47,8 @@ class AuthenticationApplication(object):
kube_rootca_update_strategy_policy.list_rules(),
kube_upgrade_strategy_policy.list_rules(),
sw_patch_strategy_policy.list_rules(),
sw_upgrade_strategy_policy.list_rules()
sw_upgrade_strategy_policy.list_rules(),
system_config_update_strategy_policy.list_rules()
)
rules = policy.Rules.load_rules(policy_file_contents,
default_rule,

View File

@ -0,0 +1,42 @@
# Copyright (c) 2023 Wind River Systems, Inc.
#
# 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
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# SPDX-License-Identifier: Apache-2.0
from nfv_vim.api.acl.policies import base
POLICY_ROOT = 'nfv_api:system_config_update_strategy:%s'
system_config_update_strategy_rules = [
base.RuleDefault(
name=POLICY_ROOT % 'add',
check_str='rule:' + base.ADMIN_IN_SYSTEM_PROJECTS,
description="Add a system_config_update_strategy",
),
base.RuleDefault(
name=POLICY_ROOT % 'delete',
check_str='rule:' + base.ADMIN_IN_SYSTEM_PROJECTS,
description="Delete a system_config_update_strategy",
),
base.RuleDefault(
name=POLICY_ROOT % 'get',
check_str='rule:' + base.READER_IN_SYSTEM_PROJECTS,
description="Get a system_config_update_strategy",
)
]
def list_rules():
return system_config_update_strategy_rules

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015-2021 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -15,6 +15,7 @@ from nfv_vim.api.controllers.v1.orchestration.sw_update import KubeRootcaUpdateA
from nfv_vim.api.controllers.v1.orchestration.sw_update import KubeUpgradeAPI
from nfv_vim.api.controllers.v1.orchestration.sw_update import SwPatchAPI
from nfv_vim.api.controllers.v1.orchestration.sw_update import SwUpgradeAPI
from nfv_vim.api.controllers.v1.orchestration.sw_update import SystemConfigUpdateAPI
class OrchestrationDescription(wsme_types.Base):
@ -34,6 +35,8 @@ class OrchestrationDescription(wsme_types.Base):
Link.make_link('self', url, 'orchestration'),
Link.make_link('sw-patch', url, 'orchestration/sw-patch', ''),
Link.make_link('sw-upgrade', url, 'orchestration/sw-upgrade', ''),
Link.make_link('system-config-update',
url, 'orchestration/system-config-update', ''),
Link.make_link('kube-rootca-update',
url, 'orchestration/kube-rootca-update', ''),
Link.make_link('kube-upgrade',
@ -52,6 +55,8 @@ class OrchestrationAPI(rest.RestController):
return SwPatchAPI(), remainder
elif 'sw-upgrade' == key:
return SwUpgradeAPI(), remainder
elif 'system-config-update' == key:
return SystemConfigUpdateAPI(), remainder
elif 'fw-update' == key:
return FwUpdateAPI(), remainder
elif 'kube-rootca-update' == key:

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015-2021 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -8,3 +8,4 @@ from nfv_vim.api.controllers.v1.orchestration.sw_update._kube_rootca_update impo
from nfv_vim.api.controllers.v1.orchestration.sw_update._kube_upgrade import KubeUpgradeAPI # noqa: F401
from nfv_vim.api.controllers.v1.orchestration.sw_update._sw_patch import SwPatchAPI # noqa: F401
from nfv_vim.api.controllers.v1.orchestration.sw_update._sw_upgrade import SwUpgradeAPI # noqa: F401
from nfv_vim.api.controllers.v1.orchestration.sw_update._system_config_update import SystemConfigUpdateAPI # noqa: F401

View File

@ -1,4 +1,4 @@
# Copyright (c) 2015-2021 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -21,6 +21,7 @@ class SwUpdateNames(Constants):
KUBE_UPGRADE = Constant('kube-upgrade')
SW_PATCH = Constant('sw-patch')
SW_UPGRADE = Constant('sw-upgrade')
SYSTEM_CONFIG_UPDATE = Constant('system-config-update')
@six.add_metaclass(Singleton)
@ -76,7 +77,8 @@ SwUpdateNames = wsme_types.Enum(str,
SW_UPDATE_NAME.KUBE_ROOTCA_UPDATE,
SW_UPDATE_NAME.KUBE_UPGRADE,
SW_UPDATE_NAME.SW_PATCH,
SW_UPDATE_NAME.SW_UPGRADE)
SW_UPDATE_NAME.SW_UPGRADE,
SW_UPDATE_NAME.SYSTEM_CONFIG_UPDATE)
SwUpdateApplyTypes = wsme_types.Enum(str,
SW_UPDATE_APPLY_TYPE.SERIAL,
SW_UPDATE_APPLY_TYPE.PARALLEL,

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015-2022 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -19,6 +19,7 @@ from nfv_vim.api.acl.policies import kube_upgrade_strategy_policy
from nfv_vim.api.acl.policies import sw_patch_strategy_policy
from nfv_vim.api.acl.policies import sw_update_strategy_policy
from nfv_vim.api.acl.policies import sw_upgrade_strategy_policy
from nfv_vim.api.acl.policies import system_config_update_strategy_policy
from nfv_vim.api.acl import policy
from nfv_vim import rpc
@ -41,6 +42,7 @@ MAX_PARALLEL_FW_UPDATE_HOSTS = 5
MAX_PARALLEL_KUBE_ROOTCA_UPDATE_HOSTS = 10
MAX_PARALLEL_KUBE_UPGRADE_HOSTS = 10
MAX_PARALLEL_PATCH_HOSTS = 100
MAX_PARALLEL_SYSTEM_CONFIG_UPDATE_HOSTS = 100
MAX_PARALLEL_UPGRADE_HOSTS = 10
@ -50,6 +52,8 @@ def _get_sw_update_type_from_path(path):
return SW_UPDATE_NAME.SW_PATCH
elif 'sw-upgrade' in split_path:
return SW_UPDATE_NAME.SW_UPGRADE
elif 'system-config-update' in split_path:
return SW_UPDATE_NAME.SYSTEM_CONFIG_UPDATE
elif 'fw-update' in split_path:
return SW_UPDATE_NAME.FW_UPDATE
elif 'kube-rootca-update' in split_path:
@ -193,6 +197,27 @@ class SwUpdateStrategyDeleteData(wsme_types.Base):
default=False)
class SystemConfigUpdateStrategyCreateData(wsme_types.Base):
"""
System Config Update Strategy - Create Data
"""
controller_apply_type = wsme_types.wsattr(SwUpdateApplyTypes, mandatory=True,
name='controller-apply-type')
storage_apply_type = wsme_types.wsattr(SwUpdateApplyTypes, mandatory=True,
name='storage-apply-type')
worker_apply_type = wsme_types.wsattr(SwUpdateApplyTypes, mandatory=True,
name='worker-apply-type')
max_parallel_worker_hosts = wsme_types.wsattr(
int, mandatory=False, name='max-parallel-worker-hosts')
default_instance_action = wsme_types.wsattr(SwUpdateInstanceActionTypes,
mandatory=True,
name='default-instance-action')
alarm_restrictions = wsme_types.wsattr(
SwUpdateAlarmRestrictionTypes, mandatory=False,
default=SW_UPDATE_ALARM_RESTRICTION_TYPES.STRICT,
name='alarm-restrictions')
class FwUpdateStrategyCreateData(wsme_types.Base):
"""
Firmware Update Strategy - Create Data
@ -697,6 +722,70 @@ class SwUpgradeStrategyAPI(SwUpdateStrategyAPI):
policy.check('admin_in_system_projects', {}, auth_context_dict)
class SystemConfigUpdateStrategyAPI(SwUpdateStrategyAPI):
"""
System Config Update Strategy Rest API
"""
@wsme_pecan.wsexpose(SwUpdateStrategyQueryData,
body=SystemConfigUpdateStrategyCreateData,
status_code=httplib.OK)
def post(self, request_data):
rpc_request = rpc.APIRequestCreateSwUpdateStrategy()
rpc_request.sw_update_type = _get_sw_update_type_from_path(
pecan.request.path)
rpc_request.controller_apply_type = request_data.controller_apply_type
rpc_request.storage_apply_type = request_data.storage_apply_type
rpc_request.worker_apply_type = request_data.worker_apply_type
if wsme_types.Unset != request_data.max_parallel_worker_hosts:
if request_data.max_parallel_worker_hosts < MIN_PARALLEL_HOSTS \
or request_data.max_parallel_worker_hosts > \
MAX_PARALLEL_SYSTEM_CONFIG_UPDATE_HOSTS:
return pecan.abort(
httplib.BAD_REQUEST,
"Invalid value for max-parallel-worker-hosts")
rpc_request.max_parallel_worker_hosts = \
request_data.max_parallel_worker_hosts
rpc_request.default_instance_action = request_data.default_instance_action
rpc_request.alarm_restrictions = request_data.alarm_restrictions
vim_connection = pecan.request.vim.open_connection()
vim_connection.send(rpc_request.serialize())
msg = vim_connection.receive(timeout_in_secs=30)
if msg is None:
DLOG.error("No response received.")
return pecan.abort(httplib.INTERNAL_SERVER_ERROR)
response = rpc.RPCMessage.deserialize(msg)
if rpc.RPC_MSG_TYPE.CREATE_SW_UPDATE_STRATEGY_RESPONSE != response.type:
DLOG.error("Unexpected message type received, msg_type=%s."
% response.type)
return pecan.abort(httplib.INTERNAL_SERVER_ERROR)
if rpc.RPC_MSG_RESULT.SUCCESS == response.result:
strategy = json.loads(response.strategy)
query_data = SwUpdateStrategyQueryData()
query_data.convert_strategy(strategy)
return query_data
elif rpc.RPC_MSG_RESULT.CONFLICT == response.result:
return pecan.abort(httplib.CONFLICT, response.error_string)
DLOG.error("Unexpected result received, result=%s." % response.result)
return pecan.abort(httplib.INTERNAL_SERVER_ERROR)
def enforce_policy(self, method_name, auth_context_dict):
"""Check policy rules for each action of this controller."""
if method_name == "delete":
policy.check(system_config_update_strategy_policy.POLICY_ROOT % "delete",
{}, auth_context_dict, exc=policy.PolicyForbidden)
elif method_name in ["get_all", "get_one"]:
policy.check(system_config_update_strategy_policy.POLICY_ROOT % "get",
{}, auth_context_dict, exc=policy.PolicyForbidden)
elif method_name == "post":
policy.check(system_config_update_strategy_policy.POLICY_ROOT % "add",
{}, auth_context_dict, exc=policy.PolicyForbidden)
else:
policy.check('admin_in_system_projects', {}, auth_context_dict)
class FwUpdateStrategyAPI(SwUpdateStrategyAPI):
"""
Firmware Update Strategy Rest API

View File

@ -0,0 +1,59 @@
#
# Copyright (c) 2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import pecan
from pecan import rest
from six.moves import http_client as httplib
from wsme import types as wsme_types
import wsmeext.pecan as wsme_pecan
from nfv_common import debug
from nfv_vim.api._link import Link
from nfv_vim.api.controllers.v1.orchestration.sw_update._sw_update_strategy \
import SystemConfigUpdateStrategyAPI
DLOG = debug.debug_get_logger('nfv_vim.api.system_config_update')
class SystemConfigUpdateDescription(wsme_types.Base):
"""
System Config Update Description
"""
id = wsme_types.text
links = wsme_types.wsattr([Link], name='links')
@classmethod
def convert(cls):
url = pecan.request.host_url
description = SystemConfigUpdateDescription()
description.id = "system-config-update"
description.links = [
Link.make_link('self',
url,
'orchestration/system-config-update'),
Link.make_link('strategy',
url,
'orchestration/system-config-update/strategy')]
return description
class SystemConfigUpdateAPI(rest.RestController):
"""
SystemConfigUpdateRest API
"""
@pecan.expose()
def _lookup(self, key, *remainder):
if 'strategy' == key:
return SystemConfigUpdateStrategyAPI(), remainder
else:
pecan.abort(httplib.NOT_FOUND)
@wsme_pecan.wsexpose(SystemConfigUpdateDescription)
def get(self):
# NOTE: The reason why convert() is being called for every
# request is because we need to get the host url from
# the request object to make the links.
return SystemConfigUpdateDescription.convert()

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2016-2021 Wind River Systems, Inc.
# Copyright (c) 2016-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -77,4 +77,8 @@ def database_sw_update_get_list():
kube_upgrade_obj = objects.KubeUpgrade(sw_update.uuid,
strategy_data)
sw_update_objs.append(kube_upgrade_obj)
elif objects.SW_UPDATE_TYPE.SYSTEM_CONFIG_UPDATE == sw_update.sw_update_type:
system_config_update_obj = objects.SystemConfigUpdate(sw_update.uuid,
strategy_data)
sw_update_objs.append(system_config_update_obj)
return sw_update_objs

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015-2020 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -127,6 +127,7 @@ nfv_vim.objects.instance_group: debug.level.verbose
nfv_vim.objects.fw_update: debug.level.info
nfv_vim.objects.kube_rootca_update: debug.level.info
nfv_vim.objects.kube_upgrade: debug.level.info
nfv_vim.objects.system_config_update: debug.level.info
nfv_vim.objects.sw_update: debug.level.verbose
nfv_vim.objects.sw_patch: debug.level.verbose
nfv_vim.objects.sw_upgrade: debug.level.verbose
@ -171,6 +172,7 @@ nfv_vim.api.kube_upgrade: debug.level.verbose
nfv_vim.api.sw_patch: debug.level.verbose
nfv_vim.api.sw_upgrade: debug.level.verbose
nfv_vim.api.sw_update.strategy: debug.level.verbose
nfv_vim.api.system_config_update: debug.level.verbose
nfv_vim.api.image: debug.level.verbose
nfv_vim.api.volume: debug.level.verbose
nfv_vim.api.virtualised_resources: debug.level.verbose

View File

@ -102,6 +102,35 @@ class SwMgmtDirector(object):
self._sw_update.strategy)
return strategy_uuid, ''
def create_system_config_update_strategy(self, controller_apply_type,
storage_apply_type, worker_apply_type,
max_parallel_worker_hosts,
default_instance_action,
alarm_restrictions, callback):
"""
Create System Config Update Strategy
"""
strategy_uuid = str(uuid.uuid4())
if self._sw_update is not None:
# Do not schedule the callback - if creation failed because a
# strategy already exists, the callback will attempt to operate
# on the old strategy, which is not what we want.
reason = "strategy already exists of type:%s" % self._sw_update._sw_update_type
return None, reason
self._sw_update = objects.SystemConfigUpdate()
success, reason = self._sw_update.strategy_build(
strategy_uuid, controller_apply_type, storage_apply_type,
worker_apply_type, max_parallel_worker_hosts,
default_instance_action,
alarm_restrictions, self._ignore_alarms,
self._single_controller)
schedule.schedule_function_call(callback, success, reason,
self._sw_update.strategy)
return strategy_uuid, ''
def create_fw_update_strategy(self,
controller_apply_type,
storage_apply_type,
@ -345,6 +374,15 @@ class SwMgmtDirector(object):
self._sw_update.handle_event(
strategy.STRATEGY_EVENT.HOST_FW_UPDATE_FAILED, host)
def system_config_update_failed(self, host):
"""
Called when a system config update for a host phase fails
"""
if self._sw_update is not None:
self._sw_update.handle_event(
strategy.STRATEGY_EVENT.SYSTEM_CONFIG_UPDATE_HOST_FAILED,
host)
def kube_host_rootca_update_failed(self, host):
"""
Called when a kube footca update for a host phase fails

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015-2021 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -342,6 +342,175 @@ _event_templates = {
}
}
},
event_log.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_START: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'event_type': event_log.EVENT_TYPE.ACTION_EVENT,
'importance': event_log.EVENT_IMPORTANCE.HIGH,
'reason_text': "System config update auto-apply start",
'exclude_event_context': [],
'event_context_data': {
event_log.EVENT_CONTEXT.ADMIN: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'reason_text': "System config update auto-apply start",
}
}
},
event_log.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_INPROGRESS: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'event_type': event_log.EVENT_TYPE.ACTION_EVENT,
'importance': event_log.EVENT_IMPORTANCE.HIGH,
'reason_text': "System config update auto-apply inprogress",
'exclude_event_context': [],
'event_context_data': {
event_log.EVENT_CONTEXT.ADMIN: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'reason_text': "System config update auto-apply inprogress",
}
}
},
event_log.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_REJECTED: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'event_type': event_log.EVENT_TYPE.ACTION_EVENT,
'importance': event_log.EVENT_IMPORTANCE.HIGH,
'reason_text': "System config update auto-apply rejected",
'exclude_event_context': [],
'event_context_data': {
event_log.EVENT_CONTEXT.ADMIN: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'reason_text': "System config update auto-apply rejected%(reason)s",
}
}
},
event_log.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_CANCELLED: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'event_type': event_log.EVENT_TYPE.ACTION_EVENT,
'importance': event_log.EVENT_IMPORTANCE.HIGH,
'reason_text': "System config update auto-apply cancelled",
'exclude_event_context': [],
'event_context_data': {
event_log.EVENT_CONTEXT.ADMIN: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'reason_text': "System config update auto-apply "
"cancelled%(reason)s",
}
}
},
event_log.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_FAILED: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'event_type': event_log.EVENT_TYPE.ACTION_EVENT,
'importance': event_log.EVENT_IMPORTANCE.HIGH,
'reason_text': "System config update auto-apply failed",
'exclude_event_context': [],
'event_context_data': {
event_log.EVENT_CONTEXT.ADMIN: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'reason_text': "System config update auto-apply "
"failed%(reason)s",
}
}
},
event_log.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_COMPLETED: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'event_type': event_log.EVENT_TYPE.ACTION_EVENT,
'importance': event_log.EVENT_IMPORTANCE.HIGH,
'reason_text': "System config update auto-apply completed",
'exclude_event_context': [],
'event_context_data': {
event_log.EVENT_CONTEXT.ADMIN: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'reason_text': "System config update auto-apply completed",
}
}
},
event_log.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORT: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'event_type': event_log.EVENT_TYPE.ACTION_EVENT,
'importance': event_log.EVENT_IMPORTANCE.HIGH,
'reason_text': "System config update auto-apply abort",
'exclude_event_context': [],
'event_context_data': {
event_log.EVENT_CONTEXT.ADMIN: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'reason_text': "System config update auto-apply abort",
}
}
},
event_log.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORTING: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'event_type': event_log.EVENT_TYPE.ACTION_EVENT,
'importance': event_log.EVENT_IMPORTANCE.HIGH,
'reason_text': "System config update auto-apply aborting",
'exclude_event_context': [],
'event_context_data': {
event_log.EVENT_CONTEXT.ADMIN: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'reason_text': "System config update auto-apply aborting",
}
}
},
event_log.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORT_REJECTED: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'event_type': event_log.EVENT_TYPE.ACTION_EVENT,
'importance': event_log.EVENT_IMPORTANCE.HIGH,
'reason_text': "System config update auto-apply abort rejected",
'exclude_event_context': [],
'event_context_data': {
event_log.EVENT_CONTEXT.ADMIN: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'reason_text': "System config update auto-apply abort "
"rejected%(reason)s",
}
}
},
event_log.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORT_FAILED: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'event_type': event_log.EVENT_TYPE.ACTION_EVENT,
'importance': event_log.EVENT_IMPORTANCE.HIGH,
'reason_text': "System config update auto-apply abort failed",
'exclude_event_context': [],
'event_context_data': {
event_log.EVENT_CONTEXT.ADMIN: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'reason_text': "System config update auto-apply abort "
"failed%(reason)s",
}
}
},
event_log.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORTED: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'event_type': event_log.EVENT_TYPE.ACTION_EVENT,
'importance': event_log.EVENT_IMPORTANCE.HIGH,
'reason_text': "System config update auto-apply aborted",
'exclude_event_context': [],
'event_context_data': {
event_log.EVENT_CONTEXT.ADMIN: {
'entity_type': "orchestration",
'entity': "orchestration=system-config-update",
'reason_text': "System config update auto-apply aborted",
}
}
},
event_log.EVENT_ID.KUBE_ROOTCA_UPDATE_AUTO_APPLY_START: {
'entity_type': "orchestration",
'entity': "orchestration=kube-rootca update",

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015-2021 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -196,6 +196,9 @@ def _vim_api_message_handler(connection, msg):
elif rpc.RPC_MSG_TYPE.CREATE_SW_UPGRADE_STRATEGY_REQUEST == msg.type:
vim_sw_update_api_create_strategy(connection, msg)
elif rpc.RPC_MSG_TYPE.CREATE_SYSTEM_CONFIG_UPDATE_STRATEGY_REQUEST == msg.type:
vim_sw_update_api_create_strategy(connection, msg)
elif rpc.RPC_MSG_TYPE.APPLY_SW_UPDATE_STRATEGY_REQUEST == msg.type:
vim_sw_update_api_apply_strategy(connection, msg)

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015-2021 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -122,6 +122,8 @@ def _nfvi_sw_update_get_callback():
sw_update_type = 'sw-patch'
elif sw_update.sw_update_type == objects.SW_UPDATE_TYPE.SW_UPGRADE:
sw_update_type = 'sw-upgrade'
elif sw_update.sw_update_type == objects.SW_UPDATE_TYPE.SYSTEM_CONFIG_UPDATE:
sw_update_type = 'system-config-update'
elif sw_update.sw_update_type == objects.SW_UPDATE_TYPE.FW_UPDATE:
sw_update_type = 'fw-update'
elif sw_update.sw_update_type == objects.SW_UPDATE_TYPE.KUBE_ROOTCA_UPDATE:

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015-2021 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -139,6 +139,13 @@ def vim_sw_update_api_create_strategy(connection, msg):
alarm_restrictions,
to_version,
_vim_sw_update_api_create_strategy_callback)
elif 'system-config-update' == msg.sw_update_type:
uuid, reason = sw_mgmt_director.create_system_config_update_strategy(
controller_apply_type, storage_apply_type,
worker_apply_type, max_parallel_worker_hosts,
default_instance_action,
alarm_restrictions,
_vim_sw_update_api_create_strategy_callback)
else:
DLOG.error("Invalid message name: %s" % msg.sw_update_type)
response = rpc.APIResponseCreateSwUpdateStrategy()
@ -205,6 +212,8 @@ def vim_sw_update_api_apply_strategy(connection, msg):
sw_update_type = objects.SW_UPDATE_TYPE.KUBE_ROOTCA_UPDATE
elif 'kube-upgrade' == msg.sw_update_type:
sw_update_type = objects.SW_UPDATE_TYPE.KUBE_UPGRADE
elif 'system-config-update' == msg.sw_update_type:
sw_update_type = objects.SW_UPDATE_TYPE.SYSTEM_CONFIG_UPDATE
else:
DLOG.error("Invalid message name: %s" % msg.sw_update_type)
sw_update_type = 'unknown'
@ -264,6 +273,8 @@ def vim_sw_update_api_abort_strategy(connection, msg):
sw_update_type = objects.SW_UPDATE_TYPE.KUBE_ROOTCA_UPDATE
elif 'kube-upgrade' == msg.sw_update_type:
sw_update_type = objects.SW_UPDATE_TYPE.KUBE_UPGRADE
elif 'system-config-update' == msg.sw_update_type:
sw_update_type = objects.SW_UPDATE_TYPE.SYSTEM_CONFIG_UPDATE
else:
DLOG.error("Invalid message name: %s" % msg.sw_update_type)
sw_update_type = 'unknown'
@ -320,6 +331,8 @@ def vim_sw_update_api_delete_strategy(connection, msg):
sw_update_type = objects.SW_UPDATE_TYPE.KUBE_ROOTCA_UPDATE
elif 'kube-upgrade' == msg.sw_update_type:
sw_update_type = objects.SW_UPDATE_TYPE.KUBE_UPGRADE
elif 'system-config-update' == msg.sw_update_type:
sw_update_type = objects.SW_UPDATE_TYPE.SYSTEM_CONFIG_UPDATE
else:
DLOG.error("Invalid message name: %s" % msg.sw_update_type)
sw_update_type = 'unknown'
@ -355,6 +368,8 @@ def vim_sw_update_api_get_strategy(connection, msg):
sw_update_type = objects.SW_UPDATE_TYPE.KUBE_ROOTCA_UPDATE
elif 'kube-upgrade' == msg.sw_update_type:
sw_update_type = objects.SW_UPDATE_TYPE.KUBE_UPGRADE
elif 'system-config-update' == msg.sw_update_type:
sw_update_type = objects.SW_UPDATE_TYPE.SYSTEM_CONFIG_UPDATE
else:
DLOG.error("Invalid message name: %s" % msg.sw_update_type)
sw_update_type = 'unknown'

View File

@ -106,6 +106,7 @@ from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_get_kube_rootca_update
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_get_kube_upgrade # noqa: F401
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_get_kube_version_list # noqa: F401
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_get_logs # noqa: F401
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_get_system_config_unlock_request # noqa: F401
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_get_system_info # noqa: F401
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_get_system_state # noqa: F401
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_get_terminating_pods # noqa: F401
@ -129,6 +130,7 @@ from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_kube_upgrade_complete
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_kube_upgrade_download_images # noqa: F401
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_kube_upgrade_networking # noqa: F401
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_kube_upgrade_start # noqa: F401
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_list_deployment_hosts # noqa: F401
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_lock_host # noqa: F401
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_notify_host_failed # noqa: F401
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_notify_host_services_delete_failed # noqa: F401

View File

@ -59,6 +59,35 @@ def nfvi_get_host(host_uuid, host_name, callback):
return cmd_id
def nfvi_get_deployment_host(host_name, callback):
"""
Get host resource from deployment namespace
"""
cmd_id = _infrastructure_plugin.invoke_plugin('get_deployment_host',
host_name,
callback=callback)
return cmd_id
def nfvi_list_deployment_hosts(callback):
"""
Get host resource from deployment namespace
"""
cmd_id = _infrastructure_plugin.invoke_plugin('list_deployment_hosts',
callback=callback)
return cmd_id
def nfvi_get_system_config_unlock_request(host_names, callback):
"""
Get host unlock request from deployment namespace
"""
cmd_id = _infrastructure_plugin.invoke_plugin('get_system_config_unlock_request',
host_names,
callback=callback)
return cmd_id
def nfvi_get_host_devices(host_uuid, host_name, callback):
"""
Get host device list details

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015-2021 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -22,6 +22,7 @@ from nfv_vim.nfvi.objects.v1._host_fw_update import HostFwUpdate # noqa: F401
from nfv_vim.nfvi.objects.v1._host_group import HOST_GROUP_POLICY # noqa: F401
from nfv_vim.nfvi.objects.v1._host_group import HostGroup # noqa: F401
from nfv_vim.nfvi.objects.v1._host_sw_patch import HostSwPatch # noqa: F401
from nfv_vim.nfvi.objects.v1._host_system_config_update import HostSystemConfigUpdate # noqa: F401
from nfv_vim.nfvi.objects.v1._hypervisor import Hypervisor # noqa: F401
from nfv_vim.nfvi.objects.v1._hypervisor import HYPERVISOR_ADMIN_STATE # noqa: F401
from nfv_vim.nfvi.objects.v1._hypervisor import HYPERVISOR_OPER_STATE # noqa: F401

View File

@ -0,0 +1,16 @@
#
# Copyright (c) 2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
from nfv_vim.nfvi.objects.v1._object import ObjectData
class HostSystemConfigUpdate(ObjectData):
"""
NFVI Host System Config Update Object
"""
def __init__(self, name, unlock_request):
super(HostSystemConfigUpdate, self).__init__('1.0.0')
self.update(dict(name=name,
unlock_request=unlock_request))

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015-2021 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -40,6 +40,7 @@ from nfv_vim.objects._sw_update import SW_UPDATE_TYPE # noqa: F401
from nfv_vim.objects._sw_update import SwUpdate # noqa: F401
from nfv_vim.objects._sw_upgrade import SwUpgrade # noqa: F401
from nfv_vim.objects._system import System # noqa: F401
from nfv_vim.objects._system_config_update import SystemConfigUpdate # noqa: F401
from nfv_vim.objects._tenant import Tenant # noqa: F401
from nfv_vim.objects._volume import Volume # noqa: F401
from nfv_vim.objects._volume_snapshot import VolumeSnapshot # noqa: F401

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2016-2021 Wind River Systems, Inc.
# Copyright (c) 2016-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -29,6 +29,7 @@ class SwUpdateTypes(Constants):
"""
SW_PATCH = Constant('sw-patch')
SW_UPGRADE = Constant('sw-upgrade')
SYSTEM_CONFIG_UPDATE = Constant('system-config-update')
FW_UPDATE = Constant('fw-update')
KUBE_ROOTCA_UPDATE = Constant('kube-rootca-update')
KUBE_UPGRADE = Constant('kube-upgrade')

View File

@ -0,0 +1,197 @@
#
# Copyright (c) 2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
from nfv_common import debug
from nfv_common import timers
from nfv_common.helpers import coroutine
from nfv_vim import alarm
from nfv_vim import event_log
from nfv_vim import nfvi
from nfv_vim.objects._sw_update import SW_UPDATE_ALARM_TYPES
from nfv_vim.objects._sw_update import SW_UPDATE_EVENT_IDS
from nfv_vim.objects._sw_update import SW_UPDATE_TYPE
from nfv_vim.objects._sw_update import SwUpdate
DLOG = debug.debug_get_logger('nfv_vim.objects.system_config_update')
class SystemConfigUpdate(SwUpdate):
"""
System config update Object
"""
def __init__(self, sw_update_uuid=None, strategy_data=None):
super(SystemConfigUpdate, self).__init__(
sw_update_type=SW_UPDATE_TYPE.SYSTEM_CONFIG_UPDATE,
sw_update_uuid=sw_update_uuid,
strategy_data=strategy_data)
self._system_config_update_hosts = list()
def strategy_build(self,
strategy_uuid,
controller_apply_type,
storage_apply_type,
worker_apply_type,
max_parallel_worker_hosts,
default_instance_action,
alarm_restrictions,
ignore_alarms,
single_controller):
"""
Create a system config update strategy
"""
from nfv_vim import strategy
if self._strategy:
reason = "strategy already exists of type:%s" % self._sw_update_type
return False, reason
self._strategy = \
strategy.SystemConfigUpdateStrategy(strategy_uuid,
controller_apply_type,
storage_apply_type,
worker_apply_type,
max_parallel_worker_hosts,
default_instance_action,
alarm_restrictions,
ignore_alarms,
single_controller)
self._strategy.sw_update_obj = self
self._strategy.build()
self._persist()
return True, ''
def strategy_build_complete(self, success, reason):
"""
Creation of a system config update strategy complete
"""
DLOG.info("System config update strategy build complete.")
pass
@staticmethod
def alarm_type(alarm_type):
"""
Returns ALARM_TYPE corresponding to SW_UPDATE_ALARM_TYPES
"""
ALARM_TYPE_MAPPING = {
SW_UPDATE_ALARM_TYPES.APPLY_INPROGRESS:
alarm.ALARM_TYPE.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_INPROGRESS,
SW_UPDATE_ALARM_TYPES.APPLY_ABORTING:
alarm.ALARM_TYPE.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORTING,
SW_UPDATE_ALARM_TYPES.APPLY_FAILED:
alarm.ALARM_TYPE.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_FAILED,
}
return ALARM_TYPE_MAPPING[alarm_type]
@staticmethod
def event_id(event_id):
"""
Returns EVENT_ID corresponding to SW_UPDATE_EVENT_IDS
"""
EVENT_ID_MAPPING = {
SW_UPDATE_EVENT_IDS.APPLY_START:
event_log.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_START,
SW_UPDATE_EVENT_IDS.APPLY_INPROGRESS:
event_log.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_INPROGRESS,
SW_UPDATE_EVENT_IDS.APPLY_REJECTED:
event_log.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_REJECTED,
SW_UPDATE_EVENT_IDS.APPLY_CANCELLED:
event_log.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_CANCELLED,
SW_UPDATE_EVENT_IDS.APPLY_FAILED:
event_log.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_FAILED,
SW_UPDATE_EVENT_IDS.APPLY_COMPLETED:
event_log.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_COMPLETED,
SW_UPDATE_EVENT_IDS.APPLY_ABORT:
event_log.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORT,
SW_UPDATE_EVENT_IDS.APPLY_ABORTING:
event_log.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORTING,
SW_UPDATE_EVENT_IDS.APPLY_ABORT_REJECTED:
event_log.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORT_REJECTED,
SW_UPDATE_EVENT_IDS.APPLY_ABORT_FAILED:
event_log.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORT_FAILED,
SW_UPDATE_EVENT_IDS.APPLY_ABORTED:
event_log.EVENT_ID.SYSTEM_CONFIG_UPDATE_AUTO_APPLY_ABORTED,
}
return EVENT_ID_MAPPING[event_id]
def nfvi_update(self):
"""
NFVI Update
"""
if self._strategy is None:
if self._alarms:
alarm.clear_sw_update_alarm(self._alarms)
return False
if self.strategy.is_applying():
if not self._alarms:
self._alarms = alarm.raise_sw_update_alarm(
self.alarm_type(SW_UPDATE_ALARM_TYPES.APPLY_INPROGRESS))
event_log.sw_update_issue_log(
self.event_id(SW_UPDATE_EVENT_IDS.APPLY_INPROGRESS))
elif (self.strategy.is_apply_failed() or
self.strategy.is_apply_timed_out()):
for system_config_update_host in self._system_config_update_hosts:
if not self._alarms:
self._alarms = \
alarm.raise_sw_update_alarm(
self.alarm_type(SW_UPDATE_ALARM_TYPES.APPLY_FAILED))
event_log.sw_update_issue_log(
self.event_id(SW_UPDATE_EVENT_IDS.APPLY_FAILED))
break
else:
if self._alarms:
alarm.clear_sw_update_alarm(self._alarms)
return False
elif self.strategy.is_aborting():
if not self._alarms:
self._alarms = alarm.raise_sw_update_alarm(
self.alarm_type(SW_UPDATE_ALARM_TYPES.APPLY_ABORTING))
event_log.sw_update_issue_log(
self.event_id(SW_UPDATE_EVENT_IDS.APPLY_ABORTING))
else:
if self._alarms:
alarm.clear_sw_update_alarm(self._alarms)
return False
return True
@coroutine
def nfvi_audit(self):
"""
Audit NFVI layer
"""
while True:
timer_id = (yield)
DLOG.debug("Audit alarms, timer_id=%s." % timer_id)
self.nfvi_alarms_clear()
nfvi.nfvi_get_alarms(self.nfvi_alarms_callback(timer_id))
if not nfvi.nfvi_fault_mgmt_plugin_disabled():
nfvi.nfvi_get_openstack_alarms(
self.nfvi_alarms_callback(timer_id))
self._nfvi_audit_inprogress = True
while self._nfvi_audit_inprogress:
timer_id = (yield)
# nfvi_alarms_callback sets timer to 2 seconds. reset back to 30
timers.timers_reschedule_timer(timer_id, 30)
if not self.nfvi_update():
DLOG.info("Audit no longer needed.")
break
DLOG.verbose("Audit system config update still running, timer_id=%s."
% timer_id)
self._nfvi_timer_id = None

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015-2021 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -77,6 +77,7 @@ from nfv_vim.rpc._rpc_message_sw_update import APIRequestCreateKubeRootcaUpdateS
from nfv_vim.rpc._rpc_message_sw_update import APIRequestCreateKubeUpgradeStrategy # noqa: F401
from nfv_vim.rpc._rpc_message_sw_update import APIRequestCreateSwUpdateStrategy # noqa: F401
from nfv_vim.rpc._rpc_message_sw_update import APIRequestCreateSwUpgradeStrategy # noqa: F401
from nfv_vim.rpc._rpc_message_sw_update import APIRequestCreateSystemConfigUpdateStrategy # noqa: F401
from nfv_vim.rpc._rpc_message_sw_update import APIRequestDeleteSwUpdateStrategy # noqa: F401
from nfv_vim.rpc._rpc_message_sw_update import APIRequestGetSwUpdateStrategy # noqa: F401
from nfv_vim.rpc._rpc_message_sw_update import APIResponseAbortSwUpdateStrategy # noqa: F401

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015-2021 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -99,6 +99,7 @@ class _RPCMessageType(Constants):
CREATE_KUBE_ROOTCA_UPDATE_STRATEGY_REQUEST = Constant('create-kube-rootca-update-strategy-request')
CREATE_KUBE_UPGRADE_STRATEGY_REQUEST = Constant('create-kube-upgrade-strategy-request')
CREATE_SW_UPGRADE_STRATEGY_REQUEST = Constant('create-sw-upgrade-strategy-request')
CREATE_SYSTEM_CONFIG_UPDATE_STRATEGY_REQUEST = Constant('create-system-config-update-strategy-request')
CREATE_SW_UPDATE_STRATEGY_RESPONSE = Constant('create-sw-update-strategy-response')
APPLY_SW_UPDATE_STRATEGY_REQUEST = Constant('apply-sw-update-strategy-request')
APPLY_SW_UPDATE_STRATEGY_RESPONSE = Constant('apply-sw-update-strategy-response')

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015-2021 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -147,6 +147,7 @@ class RPCMessageFactory(object):
from nfv_vim.rpc._rpc_message_sw_update import APIRequestCreateKubeUpgradeStrategy
from nfv_vim.rpc._rpc_message_sw_update import APIRequestCreateSwUpdateStrategy
from nfv_vim.rpc._rpc_message_sw_update import APIRequestCreateSwUpgradeStrategy
from nfv_vim.rpc._rpc_message_sw_update import APIRequestCreateSystemConfigUpdateStrategy
from nfv_vim.rpc._rpc_message_sw_update import APIRequestDeleteSwUpdateStrategy
from nfv_vim.rpc._rpc_message_sw_update import APIRequestGetSwUpdateStrategy
from nfv_vim.rpc._rpc_message_sw_update import APIResponseAbortSwUpdateStrategy
@ -230,6 +231,7 @@ class RPCMessageFactory(object):
RPC_MSG_TYPE.CREATE_KUBE_UPGRADE_STRATEGY_REQUEST: APIRequestCreateKubeUpgradeStrategy,
RPC_MSG_TYPE.CREATE_SW_UPGRADE_STRATEGY_REQUEST: APIRequestCreateSwUpgradeStrategy,
RPC_MSG_TYPE.CREATE_SW_UPDATE_STRATEGY_RESPONSE: APIResponseCreateSwUpdateStrategy,
RPC_MSG_TYPE.CREATE_SYSTEM_CONFIG_UPDATE_STRATEGY_REQUEST: APIRequestCreateSystemConfigUpdateStrategy,
RPC_MSG_TYPE.APPLY_SW_UPDATE_STRATEGY_REQUEST: APIRequestApplySwUpdateStrategy,
RPC_MSG_TYPE.APPLY_SW_UPDATE_STRATEGY_RESPONSE: APIResponseApplySwUpdateStrategy,
RPC_MSG_TYPE.ABORT_SW_UPDATE_STRATEGY_REQUEST: APIRequestAbortSwUpdateStrategy,

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015-2021 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -138,6 +138,21 @@ class APIRequestCreateKubeUpgradeStrategy(APIRequestCreateSwUpdateStrategy):
return "create-kube-upgrade-strategy request: %s" % self.deserialize_payload
class APIRequestCreateSystemConfigUpdateStrategy(APIRequestCreateSwUpdateStrategy):
"""
RPC API Request Message - Create System Config Update Strategy
"""
def __init__(self, msg_version=RPC_MSG_VERSION.VERSION_1_0,
msg_type=RPC_MSG_TYPE.CREATE_SYSTEM_CONFIG_UPDATE_STRATEGY_REQUEST,
msg_result=RPC_MSG_RESULT.SUCCESS):
super(APIRequestCreateSystemConfigUpdateStrategy, self).__init__(
msg_version, msg_type, msg_result)
def __str__(self):
return "create-system-config-update-strategy request: %s" % \
self.deserialize_payload
class APIResponseCreateSwUpdateStrategy(RPCMessage):
"""
RPC API Response Message - Create Software Update Strategy

View File

@ -10,6 +10,7 @@ from nfv_vim.strategy._strategy import KubeUpgradeStrategy # noqa: F401
from nfv_vim.strategy._strategy import strategy_rebuild_from_dict # noqa: F401
from nfv_vim.strategy._strategy import SwPatchStrategy # noqa: F401
from nfv_vim.strategy._strategy import SwUpgradeStrategy # noqa: F401
from nfv_vim.strategy._strategy import SystemConfigUpdateStrategy # noqa: F401
from nfv_vim.strategy._strategy_defs import STRATEGY_EVENT # noqa: F401
from nfv_vim.strategy._strategy_stages import STRATEGY_STAGE_NAME # noqa: F401
from nfv_vim.strategy._strategy_steps import ApplySwPatchesStep # noqa: F401
@ -47,6 +48,7 @@ from nfv_vim.strategy._strategy_steps import QueryKubeUpgradeStep # noqa: F401
from nfv_vim.strategy._strategy_steps import QueryKubeVersionsStep # noqa: F401
from nfv_vim.strategy._strategy_steps import QuerySwPatchesStep # noqa: F401
from nfv_vim.strategy._strategy_steps import QuerySwPatchHostsStep # noqa: F401
from nfv_vim.strategy._strategy_steps import QuerySystemConfigUpdateHostsStep # noqa: F401
from nfv_vim.strategy._strategy_steps import QueryUpgradeStep # noqa: F401
from nfv_vim.strategy._strategy_steps import RebootHostsStep # noqa: F401
from nfv_vim.strategy._strategy_steps import StartInstancesStep # noqa: F401
@ -54,6 +56,7 @@ from nfv_vim.strategy._strategy_steps import StopInstancesStep # noqa: F401
from nfv_vim.strategy._strategy_steps import STRATEGY_STEP_NAME # noqa: F401
from nfv_vim.strategy._strategy_steps import SwactHostsStep # noqa: F401
from nfv_vim.strategy._strategy_steps import SwPatchHostsStep # noqa: F401
from nfv_vim.strategy._strategy_steps import SystemConfigUpdateHostsStep # noqa: F401
from nfv_vim.strategy._strategy_steps import SystemStabilizeStep # noqa: F401
from nfv_vim.strategy._strategy_steps import UnlockHostsStep # noqa: F401
from nfv_vim.strategy._strategy_steps import UpgradeActivateStep # noqa: F401

View File

@ -36,6 +36,7 @@ class StrategyNames(Constants):
FW_UPDATE = Constant('fw-update')
KUBE_ROOTCA_UPDATE = Constant('kube-rootca-update')
KUBE_UPGRADE = Constant('kube-upgrade')
SYSYTEM_CONFIG_UPDATE = Constant('system-config-update')
# Constant Instantiation
@ -433,6 +434,21 @@ class SwUpdateStrategy(strategy.Strategy):
self.sw_update_obj.strategy_abort_complete(
False, self.abort_phase.result_reason)
def report_build_failure(self, reason):
"""
Report a build failure for the strategy
todo(yuxing): report all build failure use this method
"""
DLOG.warn("Strategy Build Failed: %s" % reason)
self._state = strategy.STRATEGY_STATE.BUILD_FAILED
self.build_phase.result = strategy.STRATEGY_PHASE_RESULT.FAILED
self.build_phase.result_reason = reason
self.sw_update_obj.strategy_build_complete(
False,
self.build_phase.result_reason)
self.save()
def from_dict(self, data, build_phase=None, apply_phase=None, abort_phase=None):
"""
Initializes a software update strategy object using the given dictionary
@ -863,6 +879,54 @@ class QueryKubeVersionsMixin(QueryMixinBase):
data['nfvi_kube_versions_list_data'] = mixin_data
class QuerySystemConfigUpdateHostsMixin(QueryMixinBase):
"""This mixin is used through the QuerySystemConfigUpdateHostsMixin class"""
def initialize_mixin(self):
super(QuerySystemConfigUpdateHostsMixin, self).initialize_mixin()
self._nfvi_system_config_update_hosts = list()
@property
def nfvi_system_config_update_hosts(self):
"""
Returns the System Config Update hosts from the NFVI layer
"""
return self._nfvi_system_config_update_hosts
@nfvi_system_config_update_hosts.setter
def nfvi_system_config_update_hosts(self, nfvi_system_config_update_hosts):
"""
Save the System Config Update hosts from the NFVI Layer
"""
self._nfvi_system_config_update_hosts = nfvi_system_config_update_hosts
def mixin_from_dict(self, data):
"""
Extracts this mixin data from a dictionary
"""
super(QuerySystemConfigUpdateHostsMixin, self).mixin_from_dict(data)
from nfv_vim import nfvi
mixin_data = list()
for host_data in data['nfvi_system_config_update_hosts_data']:
host = nfvi.objects.v1.HostSystemConfigUpdate(
host_data['name'],
host_data['unlock_request'])
mixin_data.append(host)
self._nfvi_system_config_update_hosts = mixin_data
def mixin_as_dict(self, data):
"""
Updates the dictionary with this mixin data
"""
super(QuerySystemConfigUpdateHostsMixin, self).mixin_as_dict(data)
mixin_data = list()
for host in self._nfvi_system_config_update_hosts:
mixin_data.append(host.as_dict())
data['nfvi_system_config_update_hosts_data'] = mixin_data
class UpdateControllerHostsMixin(object):
def _add_update_controller_strategy_stages(self,
@ -990,6 +1054,19 @@ class PatchControllerHostsMixin(UpdateControllerHostsMixin):
strategy.SwPatchHostsStep)
class UpdateSystemConfigControllerHostsMixin(UpdateControllerHostsMixin):
def _add_system_config_controller_strategy_stages(self, controllers):
"""
Add controller system config update stages to a strategy
"""
from nfv_vim import strategy
return self._add_update_controller_strategy_stages(
controllers,
True,
strategy.STRATEGY_STAGE_NAME.SYSTEM_CONFIG_UPDATE_CONTROLLERS,
strategy.SystemConfigUpdateHostsStep)
class UpgradeKubeletControllerHostsMixin(UpdateControllerHostsMixin):
def _add_kubelet_controller_strategy_stages(self, controllers, to_version, reboot, stage_name):
from nfv_vim import strategy
@ -1064,6 +1141,19 @@ class PatchStorageHostsMixin(UpdateStorageHostsMixin):
strategy.SwPatchHostsStep)
class UpdateSystemConfigStorageHostsMixin(UpdateStorageHostsMixin):
def _add_system_config_storage_strategy_stages(self, storage_hosts):
"""
Add storage system config update stages to a strategy
"""
from nfv_vim import strategy
return self._add_update_storage_strategy_stages(
storage_hosts,
True,
strategy.STRATEGY_STAGE_NAME.SYSTEM_CONFIG_UPDATE_STORAGE_HOSTS,
strategy.SystemConfigUpdateHostsStep)
class UpdateWorkerHostsMixin(object):
"""
Adds the ability to add update steps for worker hosts to a strategy.
@ -1248,6 +1338,19 @@ class UpgradeKubeletWorkerHostsMixin(UpdateWorkerHostsMixin):
extra_args=to_version)
class UpdateSystemConfigWorkerHostsMixin(UpdateWorkerHostsMixin):
def _add_system_config_worker_strategy_stages(self, worker_hosts):
"""
Add worker system config update stages to a strategy
"""
from nfv_vim import strategy
return self._add_update_worker_strategy_stages(
worker_hosts,
True,
strategy.STRATEGY_STAGE_NAME.SYSTEM_CONFIG_UPDATE_WORKER_HOSTS,
strategy.SystemConfigUpdateHostsStep)
###################################################################
#
# The Software Patch Strategy
@ -2198,6 +2301,199 @@ class SwUpgradeStrategy(SwUpdateStrategy):
return data
###################################################################
#
# The System Config Update Strategy
#
###################################################################
class SystemConfigUpdateStrategy(SwUpdateStrategy,
QuerySystemConfigUpdateHostsMixin,
UpdateSystemConfigControllerHostsMixin,
UpdateSystemConfigStorageHostsMixin,
UpdateSystemConfigWorkerHostsMixin):
"""
System Config Update - Strategy
"""
def __init__(self, uuid, controller_apply_type, storage_apply_type,
worker_apply_type, max_parallel_worker_hosts,
default_instance_action, alarm_restrictions,
ignore_alarms, single_controller):
super(SystemConfigUpdateStrategy, self).__init__(
uuid,
STRATEGY_NAME.SYSYTEM_CONFIG_UPDATE,
controller_apply_type,
storage_apply_type,
SW_UPDATE_APPLY_TYPE.IGNORE,
worker_apply_type,
max_parallel_worker_hosts,
default_instance_action,
alarm_restrictions,
ignore_alarms)
# The following alarms will not prevent a system config update operation
IGNORE_ALARMS = ['100.103', # Memory threshold exceeded
'200.001', # Locked Host
'250.001', # System Config out of date
'260.001', # Unreconciled resource
'260.002', # Unsynchronized resource
'280.001', # Subcloud resource off-line
'280.002', # Subcloud resource out-of-sync
'280.003', # Subcloud backup failed
'500.200', # Certificate expiring soon
'700.004', # VM stopped
'750.006', # Configuration change requires reapply of an application
'900.010', # System Config Update in progress
'900.601', # System Config Update Auto Apply in progress
]
self._ignore_alarms += IGNORE_ALARMS
self._single_controller = single_controller
# initialize the variables required by the mixins
self.initialize_mixin()
def build(self):
"""
Build the strategy
"""
from nfv_vim import strategy
stage = strategy.StrategyStage(
strategy.STRATEGY_STAGE_NAME.SYSTEM_CONFIG_UPDATE_QUERY)
stage.add_step(strategy.QueryAlarmsStep(
ignore_alarms=self._ignore_alarms))
stage.add_step(strategy.QuerySystemConfigUpdateHostsStep())
self.build_phase.add_stage(stage)
super(SystemConfigUpdateStrategy, self).build()
def build_complete(self, result, result_reason):
"""
Strategy Build Complete
"""
from nfv_vim import strategy
from nfv_vim import tables
result, result_reason = \
super(SystemConfigUpdateStrategy, self).build_complete(result, result_reason)
DLOG.info("Build Complete Callback, result=%s, reason=%s."
% (result, result_reason))
if result in [strategy.STRATEGY_RESULT.SUCCESS,
strategy.STRATEGY_RESULT.DEGRADED]:
if self._nfvi_alarms:
alarm_id_set = set()
for alarm_data in self._nfvi_alarms:
alarm_id_set.add(alarm_data['alarm_id'])
alarm_id_list = ", ".join(sorted(alarm_id_set))
DLOG.warn("System config update: Active alarms present [ %s ]"
% alarm_id_list)
self.report_build_failure("active alarms present [ %s ]"
% alarm_id_list)
return
host_table = tables.tables_get_host_table()
for host in list(host_table.values()):
if HOST_PERSONALITY.WORKER in host.personality and \
HOST_PERSONALITY.CONTROLLER not in host.personality:
# Allow system config update orchestration when worker
# hosts are available, locked or powered down.
if not ((host.is_unlocked() and host.is_enabled() and
host.is_available()) or
(host.is_locked() and host.is_disabled() and
host.is_offline()) or
(host.is_locked() and host.is_disabled() and
host.is_online())):
self.report_build_failure(
"all worker hosts must be unlocked-enabled-available, "
"locked-disabled-online or locked-disabled-offline")
return
else:
# Only allow system config update orchestration when all
# controller and storage hosts are available. The config
# update wil be blocked when we do not have full redundancy.
if not (host.is_unlocked() and host.is_enabled() and
host.is_available()):
self.report_build_failure(
"all %s hosts must be unlocked-enabled-available, "
% host.personality)
return
controller_hosts = list()
storage_hosts = list()
worker_hosts = list()
host_list = list(host_table.values())
for host_resource in self.nfvi_system_config_update_hosts:
for host in host_list:
if host_resource.name == host.name:
if HOST_PERSONALITY.CONTROLLER in host.personality and \
host_resource.unlock_request != 'not_required':
controller_hosts.append(host)
elif HOST_PERSONALITY.STORAGE in host.personality and \
host_resource.unlock_request != 'not_required':
storage_hosts.append(host)
if HOST_PERSONALITY.WORKER in host.personality and \
host_resource.unlock_request != 'not_required':
worker_hosts.append(host)
host_list.remove(host)
break
STRATEGY_CREATION_COMMANDS = [
(self._add_system_config_controller_strategy_stages,
controller_hosts),
(self._add_system_config_storage_strategy_stages,
storage_hosts),
(self._add_system_config_worker_strategy_stages,
worker_hosts)
]
for add_strategy_stages_function, host_list in \
STRATEGY_CREATION_COMMANDS:
if host_list:
success, reason = add_strategy_stages_function(host_list)
if not success:
self.report_build_failure(reason)
return
if 0 == len(self.apply_phase.stages):
self.report_build_failure(
"no system config updates need to be applied")
return
else:
self.sw_update_obj.strategy_build_complete( # pylint: disable=no-member
False, self.build_phase.result_reason)
self.sw_update_obj.strategy_build_complete(True, '') # pylint: disable=no-member
self.save()
def from_dict(self, data, build_phase=None, apply_phase=None, abort_phase=None):
"""
Initializes a system config update strategy object using the given
dictionary
"""
super(SystemConfigUpdateStrategy, self).from_dict(
data, build_phase, apply_phase, abort_phase)
self._single_controller = data['single_controller']
self.mixin_from_dict(data)
return self
def as_dict(self):
"""
Represent the software upgrade strategy as a dictionary
"""
data = super(SystemConfigUpdateStrategy, self).as_dict()
data['single_controller'] = self._single_controller
self.mixin_as_dict(data)
return data
###################################################################
#
# The Firmware Update Strategy
@ -2610,21 +2906,6 @@ class KubeRootcaUpdateStrategy(SwUpdateStrategy,
# initialize the variables required by the mixins
self.initialize_mixin()
def report_build_failure(self, reason):
"""
Report a build failure for the strategy
todo(abailey): this should be in the superclass
"""
DLOG.warn("Strategy Build Failed: %s" % reason)
self._state = strategy.STRATEGY_STATE.BUILD_FAILED
self.build_phase.result = strategy.STRATEGY_PHASE_RESULT.FAILED
self.build_phase.result_reason = reason
self.sw_update_obj.strategy_build_complete(
False,
self.build_phase.result_reason)
self.save()
def build(self):
"""Build the strategy"""
from nfv_vim import strategy
@ -3444,16 +3725,6 @@ class KubeUpgradeStrategy(SwUpdateStrategy,
stage.add_step(strategy.KubeUpgradeCleanupStep())
self.apply_phase.add_stage(stage)
def report_build_failure(self, reason):
DLOG.warn("Strategy Build Failed: %s" % reason)
self._state = strategy.STRATEGY_STATE.BUILD_FAILED
self.build_phase.result = strategy.STRATEGY_PHASE_RESULT.FAILED
self.build_phase.result_reason = reason
self.sw_update_obj.strategy_build_complete(
False,
self.build_phase.result_reason)
self.save()
def get_first_host(self):
"""
This corresponds to the first host that should be updated.
@ -3685,6 +3956,8 @@ def strategy_rebuild_from_dict(data):
strategy_obj = object.__new__(SwPatchStrategy)
elif STRATEGY_NAME.SW_UPGRADE == data['name']:
strategy_obj = object.__new__(SwUpgradeStrategy)
elif STRATEGY_NAME.SYSYTEM_CONFIG_UPDATE == data['name']:
strategy_obj = object.__new__(SystemConfigUpdateStrategy)
elif STRATEGY_NAME.FW_UPDATE == data['name']:
strategy_obj = object.__new__(FwUpdateStrategy)
elif STRATEGY_NAME.KUBE_ROOTCA_UPDATE == data['name']:

View File

@ -37,6 +37,11 @@ class StrategyStageNames(Constants):
FW_UPDATE_HOSTS_QUERY = Constant('fw-update-hosts-query')
FW_UPDATE_HOST_QUERY = Constant('fw-update-host-query')
FW_UPDATE_WORKER_HOSTS = Constant('fw-update-worker-hosts')
# system config update stages
SYSTEM_CONFIG_UPDATE_QUERY = Constant('system-config-update-query')
SYSTEM_CONFIG_UPDATE_CONTROLLERS = Constant('system-config-update-controllers')
SYSTEM_CONFIG_UPDATE_STORAGE_HOSTS = Constant('system-config-update-storage-hosts')
SYSTEM_CONFIG_UPDATE_WORKER_HOSTS = Constant('system-config-update-worker-hosts')
# kube root ca update stages
KUBE_ROOTCA_UPDATE_CERT = Constant('kube-rootca-update-cert')
KUBE_ROOTCA_UPDATE_COMPLETE = Constant('kube-rootca-update-complete')

View File

@ -86,6 +86,9 @@ class StrategyStepNames(Constants):
KUBE_HOST_UPGRADE_CONTROL_PLANE = \
Constant('kube-host-upgrade-control-plane')
KUBE_HOST_UPGRADE_KUBELET = Constant('kube-host-upgrade-kubelet')
# system config update specific steps
QUERY_SYSTEM_CONFIG_UPDATE_HOSTS = Constant('query-system-config-update-hosts')
SYSTEM_CONFIG_UPDATE_HOSTS = Constant('system-config-update-hosts')
# Constant Instantiation
@ -809,6 +812,108 @@ class SwPatchHostsStep(strategy.StrategyStep):
return data
class SystemConfigUpdateHostsStep(strategy.StrategyStep):
"""
System Config Update Hosts - Strategy Step
"""
def __init__(self, hosts):
super(SystemConfigUpdateHostsStep, self).__init__(
STRATEGY_STEP_NAME.SYSTEM_CONFIG_UPDATE_HOSTS, timeout_in_secs=1800)
self._hosts = hosts
self._wait_time = 0
self._host_names = list()
self._host_uuids = list()
self._query_inprogress = False
for host in hosts:
self._host_names.append(host.name)
self._host_uuids.append(host.uuid)
@coroutine
def _query_hosts_callback(self):
"""
Query System Config Update Hosts Callback
"""
response = (yield)
DLOG.debug("Query-Hosts callback response=%s." % response)
self._query_inprogress = False
if response['completed']:
for host in response['result-data']:
if host.unlock_request != 'unlock_required':
# Keep waiting for the hosts to reach the unlock required
# status
pass
# Ready to unlock the hosts
result = strategy.STRATEGY_STEP_RESULT.SUCCESS
self.stage.step_complete(result, "")
def apply(self):
"""
System Config Update Hosts
"""
DLOG.info("Step (%s) apply for hosts %s." % (self._name,
self._host_names))
# Do nothing, wait for the callback to check the unlock request status
return strategy.STRATEGY_STEP_RESULT.WAIT, ""
def handle_event(self, event, event_data=None):
"""
Handle Host events
"""
from nfv_vim import nfvi
DLOG.debug("Step (%s) handle event (%s)." % (self._name, event))
if event == STRATEGY_EVENT.HOST_AUDIT:
if 0 == self._wait_time:
self._wait_time = timers.get_monotonic_timestamp_in_ms()
now_ms = timers.get_monotonic_timestamp_in_ms()
secs_expired = (now_ms - self._wait_time) // 1000
# Wait at least 30 seconds before checking the unlock status for
# first time
if 30 <= secs_expired and not self._query_inprogress:
self._query_inprogress = True
nfvi.nfvi_get_system_config_unlock_request(
self._host_names, self._query_hosts_callback())
return True
return False
def from_dict(self, data):
"""
Returns the system config update hosts step object initialized using
the given dictionary
"""
super(SystemConfigUpdateHostsStep, self).from_dict(data)
self._hosts = list()
self._wait_time = 0
self._host_uuids = list()
self._query_inprogress = False
self._host_names = data['entity_names']
host_table = tables.tables_get_host_table()
for host_name in self._host_names:
host = host_table.get(host_name, None)
if host is not None:
self._hosts.append(host)
self._host_uuids.append(host.uuid)
return self
def as_dict(self):
"""
Represent the system config update hosts step as a dictionary
"""
data = super(SystemConfigUpdateHostsStep, self).as_dict()
data['entity_type'] = 'hosts'
data['entity_names'] = self._host_names
data['entity_uuids'] = self._host_uuids
return data
class UpgradeHostsStep(strategy.StrategyStep):
"""
Upgrade Hosts - Strategy Step
@ -2197,6 +2302,45 @@ class QuerySwPatchHostsStep(strategy.StrategyStep):
return data
class QuerySystemConfigUpdateHostsStep(AbstractStrategyStep):
"""
Query System Config Update Hosts - Strategy Step
"""
def __init__(self):
super(QuerySystemConfigUpdateHostsStep, self).__init__(
STRATEGY_STEP_NAME.QUERY_SYSTEM_CONFIG_UPDATE_HOSTS,
timeout_in_secs=60)
@coroutine
def _query_hosts_callback(self):
"""
Query System Config Update Hosts Callback
"""
response = (yield)
DLOG.debug("Query-Hosts callback response=%s." % response)
if response['completed']:
if self.strategy is not None:
self.strategy.nfvi_system_config_update_hosts = \
response['result-data']
result = strategy.STRATEGY_STEP_RESULT.SUCCESS
self.stage.step_complete(result, "")
else:
result = strategy.STRATEGY_STEP_RESULT.FAILED
self.stage.step_complete(result, "")
def apply(self):
"""
Query System Config Update Hosts
"""
from nfv_vim import nfvi
DLOG.info("Step (%s) apply." % self._name)
nfvi.nfvi_list_deployment_hosts(self._query_hosts_callback())
return strategy.STRATEGY_STEP_RESULT.WAIT, ""
class QueryFwUpdateHostStep(strategy.StrategyStep):
"""
Query Host
@ -4711,6 +4855,13 @@ def strategy_step_rebuild_from_dict(data):
STRATEGY_STEP_NAME.QUERY_KUBE_HOST_UPGRADE: QueryKubeHostUpgradeStep,
STRATEGY_STEP_NAME.QUERY_KUBE_UPGRADE: QueryKubeUpgradeStep,
STRATEGY_STEP_NAME.QUERY_KUBE_VERSIONS: QueryKubeVersionsStep,
#
# system config update steps
#
STRATEGY_STEP_NAME.QUERY_SYSTEM_CONFIG_UPDATE_HOSTS:
QuerySystemConfigUpdateHostsStep,
STRATEGY_STEP_NAME.SYSTEM_CONFIG_UPDATE_HOSTS:
SystemConfigUpdateHostsStep,
}
obj_type = rebuild_map.get(data['name'])
if obj_type is not None: