Merge "Kubernetes Upgrade Orchestration"
This commit is contained in:
commit
a6d46eabef
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2016,2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2016-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -231,6 +231,9 @@ def create_strategy(token_id, url, strategy_name, controller_apply_type,
|
|||
elif 'fw-update' == strategy_name:
|
||||
api_cmd_payload['controller-apply-type'] = controller_apply_type
|
||||
api_cmd_payload['default-instance-action'] = default_instance_action
|
||||
elif 'kube-upgrade' == strategy_name:
|
||||
# required: 'to_version' passed to strategy as 'to-version'
|
||||
api_cmd_payload['to-version'] = kwargs['to_version']
|
||||
elif 'sw-upgrade' == strategy_name:
|
||||
if 'start_upgrade' in kwargs and kwargs['start_upgrade']:
|
||||
api_cmd_payload['start-upgrade'] = True
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2016,2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2016-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -11,6 +11,78 @@ import sys
|
|||
from nfv_client import sw_update
|
||||
|
||||
|
||||
def setup_kube_upgrade_parser(commands):
|
||||
# Kubernetes Upgrade Commands
|
||||
kube_upgrade_parser = commands.add_parser('kube-upgrade-strategy',
|
||||
help='Kubernetes Upgrade Strategy')
|
||||
kube_upgrade_parser.set_defaults(cmd_area='kube-upgrade-strategy')
|
||||
|
||||
kube_upgrade_cmds = kube_upgrade_parser.add_subparsers(
|
||||
title='Kubernetes Upgrade Commands', metavar='')
|
||||
kube_upgrade_cmds.required = True
|
||||
|
||||
kube_upgrade_create_strategy_cmd \
|
||||
= kube_upgrade_cmds.add_parser('create', help='Create a strategy')
|
||||
kube_upgrade_create_strategy_cmd.set_defaults(cmd='create')
|
||||
kube_upgrade_create_strategy_cmd.add_argument('--controller-apply-type',
|
||||
default=sw_update.APPLY_TYPE_SERIAL,
|
||||
choices=[sw_update.APPLY_TYPE_SERIAL, sw_update.APPLY_TYPE_IGNORE],
|
||||
help='defaults to serial')
|
||||
kube_upgrade_create_strategy_cmd.add_argument('--storage-apply-type',
|
||||
default=sw_update.APPLY_TYPE_SERIAL,
|
||||
choices=[sw_update.APPLY_TYPE_SERIAL, sw_update.APPLY_TYPE_IGNORE],
|
||||
help='defaults to serial')
|
||||
kube_upgrade_create_strategy_cmd.add_argument('--worker-apply-type',
|
||||
default=sw_update.APPLY_TYPE_SERIAL,
|
||||
choices=[sw_update.APPLY_TYPE_SERIAL,
|
||||
sw_update.APPLY_TYPE_PARALLEL,
|
||||
sw_update.APPLY_TYPE_IGNORE],
|
||||
help='defaults to serial')
|
||||
|
||||
kube_upgrade_create_strategy_cmd.add_argument(
|
||||
'--max-parallel-worker-hosts', type=int, choices=range(2, 6),
|
||||
help='maximum worker hosts to update in parallel')
|
||||
|
||||
kube_upgrade_create_strategy_cmd.add_argument('--instance-action',
|
||||
default=sw_update.INSTANCE_ACTION_STOP_START,
|
||||
choices=[sw_update.INSTANCE_ACTION_MIGRATE,
|
||||
sw_update.INSTANCE_ACTION_STOP_START],
|
||||
help='defaults to stop-start')
|
||||
|
||||
kube_upgrade_create_strategy_cmd.add_argument('--alarm-restrictions',
|
||||
default=sw_update.ALARM_RESTRICTIONS_STRICT,
|
||||
choices=[sw_update.ALARM_RESTRICTIONS_STRICT,
|
||||
sw_update.ALARM_RESTRICTIONS_RELAXED],
|
||||
help='defaults to strict')
|
||||
|
||||
kube_upgrade_create_strategy_cmd.add_argument(
|
||||
'--to-version', required=True, help='The kubernetes version')
|
||||
|
||||
kube_upgrade_delete_strategy_cmd \
|
||||
= kube_upgrade_cmds.add_parser('delete', help='Delete a strategy')
|
||||
kube_upgrade_delete_strategy_cmd.set_defaults(cmd='delete')
|
||||
kube_upgrade_delete_strategy_cmd.add_argument(
|
||||
'--force', action='store_true', help=argparse.SUPPRESS)
|
||||
|
||||
kube_upgrade_apply_strategy_cmd \
|
||||
= kube_upgrade_cmds.add_parser('apply', help='Apply a strategy')
|
||||
kube_upgrade_apply_strategy_cmd.set_defaults(cmd='apply')
|
||||
kube_upgrade_apply_strategy_cmd.add_argument(
|
||||
'--stage-id', default=None, help='stage identifier to apply')
|
||||
|
||||
kube_upgrade_abort_strategy_cmd \
|
||||
= kube_upgrade_cmds.add_parser('abort', help='Abort a strategy')
|
||||
kube_upgrade_abort_strategy_cmd.set_defaults(cmd='abort')
|
||||
kube_upgrade_abort_strategy_cmd.add_argument(
|
||||
'--stage-id', help='stage identifier to abort')
|
||||
|
||||
kube_upgrade_show_strategy_cmd \
|
||||
= kube_upgrade_cmds.add_parser('show', help='Show a strategy')
|
||||
kube_upgrade_show_strategy_cmd.set_defaults(cmd='show')
|
||||
kube_upgrade_show_strategy_cmd.add_argument(
|
||||
'--details', action='store_true', help='show strategy details')
|
||||
|
||||
|
||||
def process_main(argv=sys.argv[1:]): # pylint: disable=dangerous-default-value
|
||||
"""
|
||||
Client - Main
|
||||
|
@ -222,6 +294,9 @@ def process_main(argv=sys.argv[1:]): # pylint: disable=dangerous-default-value
|
|||
fw_update_show_strategy_cmd.add_argument(
|
||||
'--details', action='store_true', help='show strategy details')
|
||||
|
||||
# Register kubernetes upgrade command parser
|
||||
setup_kube_upgrade_parser(commands)
|
||||
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
if args.debug:
|
||||
|
@ -468,6 +543,78 @@ def process_main(argv=sys.argv[1:]): # pylint: disable=dangerous-default-value
|
|||
raise ValueError("Unknown command, %s, "
|
||||
"given for fw-update-strategy"
|
||||
% args.cmd)
|
||||
elif 'kube-upgrade-strategy' == args.cmd_area:
|
||||
strategy_type = sw_update.STRATEGY_NAME_KUBE_UPGRADE
|
||||
if 'create' == args.cmd:
|
||||
sw_update.create_strategy(
|
||||
args.os_auth_url,
|
||||
args.os_project_name,
|
||||
args.os_project_domain_name,
|
||||
args.os_username,
|
||||
args.os_password,
|
||||
args.os_user_domain_name,
|
||||
args.os_region_name,
|
||||
args.os_interface,
|
||||
strategy_type,
|
||||
args.controller_apply_type,
|
||||
args.storage_apply_type,
|
||||
sw_update.APPLY_TYPE_IGNORE,
|
||||
args.worker_apply_type,
|
||||
args.max_parallel_worker_hosts,
|
||||
args.instance_action,
|
||||
args.alarm_restrictions,
|
||||
to_version=args.to_version)
|
||||
|
||||
elif 'delete' == args.cmd:
|
||||
sw_update.delete_strategy(args.os_auth_url,
|
||||
args.os_project_name,
|
||||
args.os_project_domain_name,
|
||||
args.os_username,
|
||||
args.os_password,
|
||||
args.os_user_domain_name,
|
||||
args.os_region_name,
|
||||
args.os_interface,
|
||||
strategy_type,
|
||||
args.force)
|
||||
|
||||
elif 'apply' == args.cmd:
|
||||
sw_update.apply_strategy(args.os_auth_url,
|
||||
args.os_project_name,
|
||||
args.os_project_domain_name,
|
||||
args.os_username,
|
||||
args.os_password,
|
||||
args.os_user_domain_name,
|
||||
args.os_region_name,
|
||||
args.os_interface,
|
||||
strategy_type,
|
||||
args.stage_id)
|
||||
|
||||
elif 'abort' == args.cmd:
|
||||
sw_update.abort_strategy(args.os_auth_url,
|
||||
args.os_project_name,
|
||||
args.os_project_domain_name,
|
||||
args.os_username,
|
||||
args.os_password,
|
||||
args.os_user_domain_name,
|
||||
args.os_region_name,
|
||||
args.os_interface,
|
||||
strategy_type,
|
||||
args.stage_id)
|
||||
|
||||
elif 'show' == args.cmd:
|
||||
sw_update.show_strategy(args.os_auth_url,
|
||||
args.os_project_name,
|
||||
args.os_project_domain_name,
|
||||
args.os_username,
|
||||
args.os_password,
|
||||
args.os_user_domain_name,
|
||||
args.os_region_name,
|
||||
args.os_interface,
|
||||
strategy_type,
|
||||
args.details)
|
||||
else:
|
||||
raise ValueError("Unknown command, %s , given for %s"
|
||||
% args.cmd, args.cmd_area)
|
||||
else:
|
||||
raise ValueError("Unknown command area, %s, given" % args.cmd_area)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (c) 2016, 2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2016-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -15,5 +15,6 @@ from nfv_client.sw_update._sw_update import INSTANCE_ACTION_MIGRATE # noqa: F40
|
|||
from nfv_client.sw_update._sw_update import INSTANCE_ACTION_STOP_START # noqa: F401
|
||||
from nfv_client.sw_update._sw_update import show_strategy # noqa: F401
|
||||
from nfv_client.sw_update._sw_update import STRATEGY_NAME_FW_UPDATE # noqa: F401
|
||||
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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2016, 2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2016-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -9,6 +9,7 @@ from nfv_client.openstack import sw_update
|
|||
STRATEGY_NAME_SW_PATCH = 'sw-patch'
|
||||
STRATEGY_NAME_SW_UPGRADE = 'sw-upgrade'
|
||||
STRATEGY_NAME_FW_UPDATE = 'fw-update'
|
||||
STRATEGY_NAME_KUBE_UPGRADE = 'kube-upgrade'
|
||||
|
||||
APPLY_TYPE_SERIAL = 'serial'
|
||||
APPLY_TYPE_PARALLEL = 'parallel'
|
||||
|
@ -108,6 +109,8 @@ def _display_strategy(strategy, details=False):
|
|||
print("Strategy Upgrade Strategy:")
|
||||
elif strategy.name == STRATEGY_NAME_FW_UPDATE:
|
||||
print("Strategy Firmware Update Strategy:")
|
||||
elif strategy.name == STRATEGY_NAME_KUBE_UPGRADE:
|
||||
print("Strategy Kubernetes Upgrade Strategy:")
|
||||
else:
|
||||
print("Strategy Unknown Strategy:")
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2016-2017 Wind River Systems, Inc.
|
||||
# Copyright (c) 2016-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -22,6 +22,7 @@ function _swmanager()
|
|||
patch-strategy
|
||||
upgrade-strategy
|
||||
fw-update-strategy
|
||||
kube-upgrade-strategy
|
||||
"
|
||||
|
||||
if [ $COMP_CWORD -gt 1 ]; then
|
||||
|
@ -250,6 +251,88 @@ function _swmanager()
|
|||
esac
|
||||
fi
|
||||
|
||||
# Provide actions for completion
|
||||
COMPREPLY=($(compgen -W "${actions}" -- ${cur}))
|
||||
return 0
|
||||
;;
|
||||
kube-upgrade-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
|
||||
--to-version
|
||||
"
|
||||
local createopt=${prev}
|
||||
case "$createopt" in
|
||||
--controller-apply-type|--storage-apply-type)
|
||||
COMPREPLY=($(compgen -W "serial" -- ${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
|
||||
;;
|
||||
--to-version)
|
||||
COMPREPLY=( $(compgen -- ${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" -- ${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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -44,6 +44,9 @@ class _AlarmType(Constants):
|
|||
FW_UPDATE_AUTO_APPLY_INPROGRESS = Constant('fw-update-auto-apply-inprogress')
|
||||
FW_UPDATE_AUTO_APPLY_ABORTING = Constant('fw-update-auto-apply-aborting')
|
||||
FW_UPDATE_AUTO_APPLY_FAILED = Constant('fw-update-auto-apply-failed')
|
||||
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')
|
||||
|
||||
|
||||
@six.add_metaclass(Singleton)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -171,6 +171,17 @@ class _EventId(Constants):
|
|||
FW_UPDATE_AUTO_APPLY_ABORT_REJECTED = Constant('fw-update-auto-apply-abort-rejected')
|
||||
FW_UPDATE_AUTO_APPLY_ABORT_FAILED = Constant('fw-update-auto-apply-abort-failed')
|
||||
FW_UPDATE_AUTO_APPLY_ABORTED = Constant('fw-update-auto-apply-aborted')
|
||||
KUBE_UPGRADE_AUTO_APPLY_START = Constant('kube-upgrade-auto-apply-started')
|
||||
KUBE_UPGRADE_AUTO_APPLY_INPROGRESS = Constant('kube-upgrade-auto-apply-inprogress')
|
||||
KUBE_UPGRADE_AUTO_APPLY_REJECTED = Constant('kube-upgrade-auto-apply-rejected')
|
||||
KUBE_UPGRADE_AUTO_APPLY_CANCELLED = Constant('kube-upgrade-auto-apply-cancelled')
|
||||
KUBE_UPGRADE_AUTO_APPLY_FAILED = Constant('kube-upgrade-auto-apply-failed')
|
||||
KUBE_UPGRADE_AUTO_APPLY_COMPLETED = Constant('kube-upgrade-auto-apply-completed')
|
||||
KUBE_UPGRADE_AUTO_APPLY_ABORT = Constant('kube-upgrade-auto-apply-abort')
|
||||
KUBE_UPGRADE_AUTO_APPLY_ABORTING = Constant('kube-upgrade-auto-apply-aborting')
|
||||
KUBE_UPGRADE_AUTO_APPLY_ABORT_REJECTED = Constant('kube-upgrade-auto-apply-abort-rejected')
|
||||
KUBE_UPGRADE_AUTO_APPLY_ABORT_FAILED = Constant('kube-upgrade-auto-apply-abort-failed')
|
||||
KUBE_UPGRADE_AUTO_APPLY_ABORTED = Constant('kube-upgrade-auto-apply-aborted')
|
||||
|
||||
|
||||
@six.add_metaclass(Singleton)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2016 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -324,6 +324,8 @@ class StrategyStage(object):
|
|||
self._step_timer_id = None
|
||||
|
||||
step.start_date_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
DLOG.debug("Stage (%s) Step (%s) (apply) called"
|
||||
% (self.name, step.name))
|
||||
step.result, step.result_reason = step.apply()
|
||||
self._current_step = idx
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -78,6 +78,12 @@ _fm_alarm_id_mapping = dict([
|
|||
fm_constants.FM_ALARM_ID_FW_UPDATE_AUTO_APPLY_ABORTING),
|
||||
(alarm_objects_v1.ALARM_TYPE.FW_UPDATE_AUTO_APPLY_FAILED,
|
||||
fm_constants.FM_ALARM_ID_FW_UPDATE_AUTO_APPLY_FAILED),
|
||||
(alarm_objects_v1.ALARM_TYPE.KUBE_UPGRADE_AUTO_APPLY_INPROGRESS,
|
||||
fm_constants.FM_ALARM_ID_KUBE_UPGRADE_AUTO_APPLY_INPROGRESS),
|
||||
(alarm_objects_v1.ALARM_TYPE.KUBE_UPGRADE_AUTO_APPLY_ABORTING,
|
||||
fm_constants.FM_ALARM_ID_KUBE_UPGRADE_AUTO_APPLY_ABORTING),
|
||||
(alarm_objects_v1.ALARM_TYPE.KUBE_UPGRADE_AUTO_APPLY_FAILED,
|
||||
fm_constants.FM_ALARM_ID_KUBE_UPGRADE_AUTO_APPLY_FAILED),
|
||||
])
|
||||
|
||||
_fm_alarm_type_mapping = dict([
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2016,2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -334,6 +334,28 @@ _fm_event_id_mapping = dict([
|
|||
fm_constants.FM_LOG_ID_FW_UPDATE_AUTO_APPLY_ABORT_FAILED),
|
||||
(event_log_objects_v1.EVENT_ID.FW_UPDATE_AUTO_APPLY_ABORTED,
|
||||
fm_constants.FM_LOG_ID_FW_UPDATE_AUTO_APPLY_ABORTED),
|
||||
(event_log_objects_v1.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_START,
|
||||
fm_constants.FM_LOG_ID_KUBE_UPGRADE_AUTO_APPLY_START),
|
||||
(event_log_objects_v1.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_INPROGRESS,
|
||||
fm_constants.FM_LOG_ID_KUBE_UPGRADE_AUTO_APPLY_INPROGRESS),
|
||||
(event_log_objects_v1.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_REJECTED,
|
||||
fm_constants.FM_LOG_ID_KUBE_UPGRADE_AUTO_APPLY_REJECTED),
|
||||
(event_log_objects_v1.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_CANCELLED,
|
||||
fm_constants.FM_LOG_ID_KUBE_UPGRADE_AUTO_APPLY_CANCELLED),
|
||||
(event_log_objects_v1.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_FAILED,
|
||||
fm_constants.FM_LOG_ID_KUBE_UPGRADE_AUTO_APPLY_FAILED),
|
||||
(event_log_objects_v1.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_COMPLETED,
|
||||
fm_constants.FM_LOG_ID_KUBE_UPGRADE_AUTO_APPLY_COMPLETED),
|
||||
(event_log_objects_v1.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_ABORT,
|
||||
fm_constants.FM_LOG_ID_KUBE_UPGRADE_AUTO_APPLY_ABORT),
|
||||
(event_log_objects_v1.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_ABORTING,
|
||||
fm_constants.FM_LOG_ID_KUBE_UPGRADE_AUTO_APPLY_ABORTING),
|
||||
(event_log_objects_v1.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_ABORT_REJECTED,
|
||||
fm_constants.FM_LOG_ID_KUBE_UPGRADE_AUTO_APPLY_ABORT_REJECTED),
|
||||
(event_log_objects_v1.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_ABORT_FAILED,
|
||||
fm_constants.FM_LOG_ID_KUBE_UPGRADE_AUTO_APPLY_ABORT_FAILED),
|
||||
(event_log_objects_v1.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_ABORTED,
|
||||
fm_constants.FM_LOG_ID_KUBE_UPGRADE_AUTO_APPLY_ABORTED),
|
||||
])
|
||||
|
||||
_fm_event_type_mapping = dict([
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -839,6 +839,704 @@ class NFVIInfrastructureAPI(nfvi.api.v1.NFVIInfrastructureAPI):
|
|||
callback.send(response)
|
||||
callback.close()
|
||||
|
||||
def _extract_kube_host_upgrade_list(self,
|
||||
kube_host_upgrade_list,
|
||||
host_list):
|
||||
"""
|
||||
Return a list of KubeHostUpgrade objects from sysinv api results.
|
||||
"""
|
||||
|
||||
# Map the ID to the uuid from host_list
|
||||
host_map = dict()
|
||||
for host in host_list:
|
||||
host_map[host['id']] = host['uuid']
|
||||
result_list = []
|
||||
for host_data in kube_host_upgrade_list:
|
||||
host_uuid = host_map[host_data['host_id']]
|
||||
result_list.append(
|
||||
nfvi.objects.v1.KubeHostUpgrade(
|
||||
host_data['host_id'],
|
||||
host_uuid,
|
||||
host_data['target_version'],
|
||||
host_data['control_plane_version'],
|
||||
host_data['kubelet_version'],
|
||||
host_data['status'])
|
||||
)
|
||||
return result_list
|
||||
|
||||
def get_kube_host_upgrade_list(self, future, callback):
|
||||
"""
|
||||
Get information about the kube host upgrade list from the plugin
|
||||
"""
|
||||
response = dict()
|
||||
response['completed'] = False
|
||||
response['reason'] = ''
|
||||
|
||||
activity = "SysInv get-kube-host-upgrades"
|
||||
|
||||
try:
|
||||
future.set_timeouts(config.CONF.get('nfvi-timeouts', None))
|
||||
|
||||
if self._platform_token is None or \
|
||||
self._platform_token.is_expired():
|
||||
future.work(openstack.get_token, self._platform_directory)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete() or \
|
||||
future.result.data is None:
|
||||
DLOG.error("OpenStack get-token did not complete.")
|
||||
return
|
||||
|
||||
self._platform_token = future.result.data
|
||||
|
||||
# Query the kube host upgrade list
|
||||
future.work(sysinv.get_kube_host_upgrades, self._platform_token)
|
||||
future.result = (yield)
|
||||
if not future.result.is_complete():
|
||||
DLOG.error("Sysinv Get Kube Host Upgrades did not complete.")
|
||||
return
|
||||
kube_host_upgrade_list = future.result.data["kube_host_upgrades"]
|
||||
|
||||
# Also query the host list, kube_host_upgrades does not have uuid
|
||||
future.work(sysinv.get_hosts, self._platform_token)
|
||||
future.result = (yield)
|
||||
if not future.result.is_complete():
|
||||
DLOG.error("Sysinv Get-Hosts did not complete.")
|
||||
return
|
||||
host_list = future.result.data["ihosts"]
|
||||
|
||||
results_obj = \
|
||||
self._extract_kube_host_upgrade_list(kube_host_upgrade_list,
|
||||
host_list)
|
||||
response['result-data'] = results_obj
|
||||
response['completed'] = True
|
||||
|
||||
except exceptions.OpenStackRestAPIException as e:
|
||||
if httplib.UNAUTHORIZED == e.http_status_code:
|
||||
response['error-code'] = nfvi.NFVI_ERROR_CODE.TOKEN_EXPIRED
|
||||
if self._platform_token is not None:
|
||||
self._platform_token.set_expired()
|
||||
|
||||
else:
|
||||
DLOG.exception("Caught exception kube host upgrade list err=%s"
|
||||
% e)
|
||||
except Exception as e:
|
||||
DLOG.exception("Caught exception kube host upgrade list err=%s"
|
||||
% e)
|
||||
finally:
|
||||
callback.send(response)
|
||||
callback.close()
|
||||
|
||||
def _extract_kube_upgrade(self, kube_upgrade_data_list):
|
||||
"""
|
||||
Return a KubeUpgrade object from sysinv api results.
|
||||
|
||||
Returns None if there are no items in the list.
|
||||
Returns first kube upgrade object, but the API should never return
|
||||
more than one object.
|
||||
"""
|
||||
|
||||
if 1 < len(kube_upgrade_data_list):
|
||||
DLOG.critical("Too many kube upgrades returned, num=%i"
|
||||
% len(kube_upgrade_data_list))
|
||||
|
||||
elif 0 == len(kube_upgrade_data_list):
|
||||
DLOG.info("No kube upgrade exists, num=%i"
|
||||
% len(kube_upgrade_data_list))
|
||||
|
||||
kube_upgrade_obj = None
|
||||
for kube_upgrade_data in kube_upgrade_data_list:
|
||||
kube_upgrade_obj = nfvi.objects.v1.KubeUpgrade(
|
||||
kube_upgrade_data['state'],
|
||||
kube_upgrade_data['from_version'],
|
||||
kube_upgrade_data['to_version'])
|
||||
break
|
||||
return kube_upgrade_obj
|
||||
|
||||
def get_kube_upgrade(self, future, callback):
|
||||
"""
|
||||
Get information about the kube upgrade from the plugin
|
||||
"""
|
||||
response = dict()
|
||||
response['completed'] = False
|
||||
response['reason'] = ''
|
||||
action_type = 'get-kube-upgrade'
|
||||
|
||||
try:
|
||||
future.set_timeouts(config.CONF.get('nfvi-timeouts', None))
|
||||
|
||||
if self._platform_token is None or \
|
||||
self._platform_token.is_expired():
|
||||
future.work(openstack.get_token, self._platform_directory)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete() or \
|
||||
future.result.data is None:
|
||||
DLOG.error("OpenStack get-token did not complete.")
|
||||
return
|
||||
|
||||
self._platform_token = future.result.data
|
||||
|
||||
future.work(sysinv.get_kube_upgrade, self._platform_token)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete():
|
||||
DLOG.error("SysInv get-kube-upgrade did not complete.")
|
||||
return
|
||||
|
||||
kube_upgrade_data_list = future.result.data['kube_upgrades']
|
||||
kube_upgrade_obj = \
|
||||
self._extract_kube_upgrade(kube_upgrade_data_list)
|
||||
response['result-data'] = kube_upgrade_obj
|
||||
response['completed'] = True
|
||||
|
||||
except exceptions.OpenStackRestAPIException as e:
|
||||
if httplib.UNAUTHORIZED == e.http_status_code:
|
||||
response['error-code'] = nfvi.NFVI_ERROR_CODE.TOKEN_EXPIRED
|
||||
if self._platform_token is not None:
|
||||
self._platform_token.set_expired()
|
||||
|
||||
else:
|
||||
DLOG.exception("Caught API exception while trying %s. error=%s"
|
||||
% (action_type, e))
|
||||
|
||||
except Exception as e:
|
||||
DLOG.exception("Caught exception while trying %s. error=%s"
|
||||
% (action_type, e))
|
||||
|
||||
finally:
|
||||
callback.send(response)
|
||||
callback.close()
|
||||
|
||||
def _extract_kube_version(self, kube_data):
|
||||
"""
|
||||
Return a KubeVersion from sysinv API results.
|
||||
"""
|
||||
# sysinv api returns a field called 'version' which is a reserved field
|
||||
# in vim object data structure. It is stored as kube_version
|
||||
return nfvi.objects.v1.KubeVersion(kube_data['version'],
|
||||
kube_data['state'],
|
||||
kube_data['target'],
|
||||
kube_data['upgrade_from'],
|
||||
kube_data['downgrade_to'],
|
||||
kube_data['applied_patches'],
|
||||
kube_data['available_patches'])
|
||||
|
||||
def get_kube_version_list(self, future, callback):
|
||||
"""
|
||||
Get information about the kube versions list from the plugin
|
||||
"""
|
||||
response = dict()
|
||||
response['completed'] = False
|
||||
response['reason'] = ''
|
||||
action_type = 'get-kube-versions'
|
||||
|
||||
try:
|
||||
future.set_timeouts(config.CONF.get('nfvi-timeouts', None))
|
||||
if self._platform_token is None or \
|
||||
self._platform_token.is_expired():
|
||||
future.work(openstack.get_token, self._platform_directory)
|
||||
future.result = (yield)
|
||||
if not future.result.is_complete() or \
|
||||
future.result.data is None:
|
||||
DLOG.error("OpenStack get-token did not complete.")
|
||||
return
|
||||
self._platform_token = future.result.data
|
||||
|
||||
# get_kube_versions only returns a limited amount of data about the
|
||||
# kubernetes versions. Individual API calls get the patch info.
|
||||
future.work(sysinv.get_kube_versions, self._platform_token)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete():
|
||||
DLOG.error("%s did not complete." % action_type)
|
||||
return
|
||||
|
||||
# walk the list of versions and get the patch info
|
||||
kube_versions_list = list()
|
||||
limited_kube_version_list = future.result.data['kube_versions']
|
||||
for kube_list_entry in limited_kube_version_list:
|
||||
kube_ver = kube_list_entry['version']
|
||||
future.work(sysinv.get_kube_version,
|
||||
self._platform_token,
|
||||
kube_ver)
|
||||
future.result = (yield)
|
||||
if not future.result.is_complete():
|
||||
DLOG.error("%s for version:%s did not complete."
|
||||
% (action_type, kube_ver))
|
||||
return
|
||||
# returns a single object
|
||||
kube_ver_data = future.result.data
|
||||
kube_versions_list.append(
|
||||
self._extract_kube_version(kube_ver_data))
|
||||
|
||||
response['result-data'] = kube_versions_list
|
||||
response['completed'] = True
|
||||
|
||||
except exceptions.OpenStackRestAPIException as e:
|
||||
if httplib.UNAUTHORIZED == e.http_status_code:
|
||||
response['error-code'] = nfvi.NFVI_ERROR_CODE.TOKEN_EXPIRED
|
||||
if self._platform_token is not None:
|
||||
self._platform_token.set_expired()
|
||||
else:
|
||||
DLOG.exception("Caught API exception while trying %s. error=%s"
|
||||
% (action_type, e))
|
||||
except Exception as e:
|
||||
DLOG.exception("Caught exception while trying %s. error=%s"
|
||||
% (action_type, e))
|
||||
finally:
|
||||
callback.send(response)
|
||||
callback.close()
|
||||
|
||||
def kube_host_upgrade_control_plane(self,
|
||||
future,
|
||||
host_uuid,
|
||||
host_name,
|
||||
force,
|
||||
callback):
|
||||
"""
|
||||
Start kube host upgrade 'control plane' for a particular controller
|
||||
"""
|
||||
response = dict()
|
||||
response['completed'] = False
|
||||
response['host_uuid'] = host_uuid
|
||||
response['host_name'] = host_name
|
||||
response['reason'] = ''
|
||||
action_type = 'kube-host-upgrade-control-plane'
|
||||
sysinv_method = sysinv.kube_host_upgrade_control_plane
|
||||
|
||||
try:
|
||||
future.set_timeouts(config.CONF.get('nfvi-timeouts', None))
|
||||
|
||||
if self._platform_token is None or \
|
||||
self._platform_token.is_expired():
|
||||
future.work(openstack.get_token, self._platform_directory)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete() or \
|
||||
future.result.data is None:
|
||||
DLOG.error("OpenStack get-token did not complete.")
|
||||
return
|
||||
|
||||
self._platform_token = future.result.data
|
||||
|
||||
# invoke the actual kube_host_upgrade method
|
||||
future.work(sysinv_method,
|
||||
self._platform_token,
|
||||
host_uuid,
|
||||
force)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete():
|
||||
DLOG.error("%s did not complete." % action_type)
|
||||
return
|
||||
# result was a host object. Need to query to get kube upgrade obj
|
||||
future.work(sysinv.get_kube_upgrade, self._platform_token)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete():
|
||||
DLOG.error("SysInv get-kube-upgrade did not complete.")
|
||||
return
|
||||
|
||||
kube_upgrade_data_list = future.result.data['kube_upgrades']
|
||||
kube_upgrade_obj = \
|
||||
self._extract_kube_upgrade(kube_upgrade_data_list)
|
||||
response['result-data'] = kube_upgrade_obj
|
||||
response['completed'] = True
|
||||
|
||||
except exceptions.OpenStackRestAPIException as e:
|
||||
if httplib.UNAUTHORIZED == e.http_status_code:
|
||||
response['error-code'] = nfvi.NFVI_ERROR_CODE.TOKEN_EXPIRED
|
||||
if self._platform_token is not None:
|
||||
self._platform_token.set_expired()
|
||||
|
||||
else:
|
||||
DLOG.exception("Caught API exception while trying %s. error=%s"
|
||||
% (action_type, e))
|
||||
response['reason'] = e.http_response_reason
|
||||
|
||||
except Exception as e:
|
||||
DLOG.exception("Caught exception while trying %s. error=%s"
|
||||
% (action_type, e))
|
||||
|
||||
finally:
|
||||
callback.send(response)
|
||||
callback.close()
|
||||
|
||||
def kube_host_upgrade_kubelet(self,
|
||||
future,
|
||||
host_uuid,
|
||||
host_name,
|
||||
force,
|
||||
callback):
|
||||
"""
|
||||
Start kube host upgrade 'kubelet' for a particular host
|
||||
"""
|
||||
response = dict()
|
||||
response['completed'] = False
|
||||
response['host_uuid'] = host_uuid
|
||||
response['host_name'] = host_name
|
||||
response['reason'] = ''
|
||||
action_type = 'kube-host-upgrade-kubelet'
|
||||
sysinv_method = sysinv.kube_host_upgrade_kubelet
|
||||
|
||||
try:
|
||||
future.set_timeouts(config.CONF.get('nfvi-timeouts', None))
|
||||
|
||||
if self._platform_token is None or \
|
||||
self._platform_token.is_expired():
|
||||
future.work(openstack.get_token, self._platform_directory)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete() or \
|
||||
future.result.data is None:
|
||||
DLOG.error("OpenStack get-token did not complete.")
|
||||
return
|
||||
|
||||
self._platform_token = future.result.data
|
||||
|
||||
# invoke the actual kube_host_upgrade method
|
||||
future.work(sysinv_method,
|
||||
self._platform_token,
|
||||
host_uuid,
|
||||
force)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete():
|
||||
DLOG.error("%s did not complete." % action_type)
|
||||
return
|
||||
# result was a host object. Need to query to get kube upgrade obj
|
||||
future.work(sysinv.get_kube_upgrade, self._platform_token)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete():
|
||||
DLOG.error("SysInv get-kube-upgrade did not complete.")
|
||||
return
|
||||
|
||||
kube_upgrade_data_list = future.result.data['kube_upgrades']
|
||||
kube_upgrade_obj = \
|
||||
self._extract_kube_upgrade(kube_upgrade_data_list)
|
||||
response['result-data'] = kube_upgrade_obj
|
||||
response['completed'] = True
|
||||
|
||||
except exceptions.OpenStackRestAPIException as e:
|
||||
if httplib.UNAUTHORIZED == e.http_status_code:
|
||||
response['error-code'] = nfvi.NFVI_ERROR_CODE.TOKEN_EXPIRED
|
||||
if self._platform_token is not None:
|
||||
self._platform_token.set_expired()
|
||||
|
||||
else:
|
||||
DLOG.exception("Caught API exception while trying %s. error=%s"
|
||||
% (action_type, e))
|
||||
response['reason'] = e.http_response_reason
|
||||
|
||||
except Exception as e:
|
||||
DLOG.exception("Caught exception while trying %s. error=%s"
|
||||
% (action_type, e))
|
||||
|
||||
finally:
|
||||
callback.send(response)
|
||||
callback.close()
|
||||
|
||||
def kube_upgrade_cleanup(self, future, callback):
|
||||
"""
|
||||
kube upgrade cleanup
|
||||
"""
|
||||
response = dict()
|
||||
response['completed'] = False
|
||||
response['reason'] = ''
|
||||
action_type = 'kube-upgrade-cleanup'
|
||||
|
||||
try:
|
||||
future.set_timeouts(config.CONF.get('nfvi-timeouts', None))
|
||||
|
||||
if self._platform_token is None or \
|
||||
self._platform_token.is_expired():
|
||||
future.work(openstack.get_token, self._platform_directory)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete() or \
|
||||
future.result.data is None:
|
||||
DLOG.error("OpenStack get-token did not complete.")
|
||||
return
|
||||
|
||||
self._platform_token = future.result.data
|
||||
|
||||
future.work(sysinv.kube_upgrade_cleanup, self._platform_token)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete():
|
||||
DLOG.error("%s did not complete." % action_type)
|
||||
return
|
||||
|
||||
# The result should be empty. no result data to report back
|
||||
response['completed'] = True
|
||||
|
||||
except exceptions.OpenStackRestAPIException as e:
|
||||
if httplib.UNAUTHORIZED == e.http_status_code:
|
||||
response['error-code'] = nfvi.NFVI_ERROR_CODE.TOKEN_EXPIRED
|
||||
if self._platform_token is not None:
|
||||
self._platform_token.set_expired()
|
||||
|
||||
else:
|
||||
DLOG.exception("Caught API exception while trying %s. error=%s"
|
||||
% (action_type, e))
|
||||
response['reason'] = e.http_response_reason
|
||||
|
||||
except Exception as e:
|
||||
DLOG.exception("Caught exception while trying %s. error=%s"
|
||||
% (action_type, e))
|
||||
|
||||
finally:
|
||||
callback.send(response)
|
||||
callback.close()
|
||||
|
||||
def kube_upgrade_complete(self, future, callback):
|
||||
"""
|
||||
kube upgrade complete
|
||||
"""
|
||||
response = dict()
|
||||
response['completed'] = False
|
||||
response['reason'] = ''
|
||||
action_type = 'kube-upgrade-complete'
|
||||
|
||||
try:
|
||||
future.set_timeouts(config.CONF.get('nfvi-timeouts', None))
|
||||
|
||||
if self._platform_token is None or \
|
||||
self._platform_token.is_expired():
|
||||
future.work(openstack.get_token, self._platform_directory)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete() or \
|
||||
future.result.data is None:
|
||||
DLOG.error("OpenStack get-token did not complete.")
|
||||
return
|
||||
|
||||
self._platform_token = future.result.data
|
||||
|
||||
future.work(sysinv.kube_upgrade_complete, self._platform_token)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete():
|
||||
DLOG.error("%s did not complete." % action_type)
|
||||
return
|
||||
|
||||
kube_upgrade_data = future.result.data
|
||||
kube_upgrade_obj = nfvi.objects.v1.KubeUpgrade(
|
||||
kube_upgrade_data['state'],
|
||||
kube_upgrade_data['from_version'],
|
||||
kube_upgrade_data['to_version'])
|
||||
|
||||
response['result-data'] = kube_upgrade_obj
|
||||
response['completed'] = True
|
||||
|
||||
except exceptions.OpenStackRestAPIException as e:
|
||||
if httplib.UNAUTHORIZED == e.http_status_code:
|
||||
response['error-code'] = nfvi.NFVI_ERROR_CODE.TOKEN_EXPIRED
|
||||
if self._platform_token is not None:
|
||||
self._platform_token.set_expired()
|
||||
|
||||
else:
|
||||
DLOG.exception("Caught API exception while trying %s. error=%s"
|
||||
% (action_type, e))
|
||||
response['reason'] = e.http_response_reason
|
||||
|
||||
except Exception as e:
|
||||
DLOG.exception("Caught exception while trying %s. error=%s"
|
||||
% (action_type, e))
|
||||
|
||||
finally:
|
||||
callback.send(response)
|
||||
callback.close()
|
||||
|
||||
def kube_upgrade_download_images(self, future, callback):
|
||||
"""
|
||||
Start kube upgrade download images
|
||||
"""
|
||||
response = dict()
|
||||
response['completed'] = False
|
||||
response['reason'] = ''
|
||||
action_type = 'kube-upgrade-download-images'
|
||||
|
||||
try:
|
||||
future.set_timeouts(config.CONF.get('nfvi-timeouts', None))
|
||||
|
||||
if self._platform_token is None or \
|
||||
self._platform_token.is_expired():
|
||||
future.work(openstack.get_token, self._platform_directory)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete() or \
|
||||
future.result.data is None:
|
||||
DLOG.error("OpenStack get-token did not complete.")
|
||||
return
|
||||
|
||||
self._platform_token = future.result.data
|
||||
|
||||
future.work(sysinv.kube_upgrade_download_images,
|
||||
self._platform_token)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete():
|
||||
DLOG.error("%s did not complete." % action_type)
|
||||
return
|
||||
|
||||
kube_upgrade_data = future.result.data
|
||||
kube_upgrade_obj = nfvi.objects.v1.KubeUpgrade(
|
||||
kube_upgrade_data['state'],
|
||||
kube_upgrade_data['from_version'],
|
||||
kube_upgrade_data['to_version'])
|
||||
|
||||
response['result-data'] = kube_upgrade_obj
|
||||
response['completed'] = True
|
||||
|
||||
except exceptions.OpenStackRestAPIException as e:
|
||||
if httplib.UNAUTHORIZED == e.http_status_code:
|
||||
response['error-code'] = nfvi.NFVI_ERROR_CODE.TOKEN_EXPIRED
|
||||
if self._platform_token is not None:
|
||||
self._platform_token.set_expired()
|
||||
|
||||
else:
|
||||
DLOG.exception("Caught API exception while trying %s. error=%s"
|
||||
% (action_type, e))
|
||||
|
||||
except Exception as e:
|
||||
DLOG.exception("Caught exception while trying %s. error=%s"
|
||||
% (action_type, e))
|
||||
|
||||
finally:
|
||||
callback.send(response)
|
||||
callback.close()
|
||||
|
||||
def kube_upgrade_networking(self, future, callback):
|
||||
"""
|
||||
Start kube upgrade networking
|
||||
"""
|
||||
response = dict()
|
||||
response['completed'] = False
|
||||
response['reason'] = ''
|
||||
action_type = 'kube-upgrade-networking'
|
||||
|
||||
try:
|
||||
future.set_timeouts(config.CONF.get('nfvi-timeouts', None))
|
||||
|
||||
if self._platform_token is None or \
|
||||
self._platform_token.is_expired():
|
||||
future.work(openstack.get_token, self._platform_directory)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete() or \
|
||||
future.result.data is None:
|
||||
DLOG.error("OpenStack get-token did not complete.")
|
||||
return
|
||||
|
||||
self._platform_token = future.result.data
|
||||
|
||||
future.work(sysinv.kube_upgrade_networking, self._platform_token)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete():
|
||||
DLOG.error("%s did not complete." % action_type)
|
||||
return
|
||||
|
||||
kube_upgrade_data = future.result.data
|
||||
kube_upgrade_obj = nfvi.objects.v1.KubeUpgrade(
|
||||
kube_upgrade_data['state'],
|
||||
kube_upgrade_data['from_version'],
|
||||
kube_upgrade_data['to_version'])
|
||||
|
||||
response['result-data'] = kube_upgrade_obj
|
||||
response['completed'] = True
|
||||
|
||||
except exceptions.OpenStackRestAPIException as e:
|
||||
if httplib.UNAUTHORIZED == e.http_status_code:
|
||||
response['error-code'] = nfvi.NFVI_ERROR_CODE.TOKEN_EXPIRED
|
||||
if self._platform_token is not None:
|
||||
self._platform_token.set_expired()
|
||||
|
||||
else:
|
||||
DLOG.exception("Caught API exception while trying %s. error=%s"
|
||||
% (action_type, e))
|
||||
|
||||
except Exception as e:
|
||||
DLOG.exception("Caught exception while trying %s. error=%s"
|
||||
% (action_type, e))
|
||||
|
||||
finally:
|
||||
callback.send(response)
|
||||
callback.close()
|
||||
|
||||
def kube_upgrade_start(self, future, to_version, force, alarm_ignore_list,
|
||||
callback):
|
||||
"""
|
||||
Start a kube upgrade
|
||||
"""
|
||||
response = dict()
|
||||
response['completed'] = False
|
||||
response['reason'] = ''
|
||||
action_type = 'kube-upgrade-start'
|
||||
|
||||
try:
|
||||
future.set_timeouts(config.CONF.get('nfvi-timeouts', None))
|
||||
|
||||
if self._platform_token is None or \
|
||||
self._platform_token.is_expired():
|
||||
future.work(openstack.get_token, self._platform_directory)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete() or \
|
||||
future.result.data is None:
|
||||
DLOG.error("OpenStack get-token did not complete.")
|
||||
return
|
||||
|
||||
self._platform_token = future.result.data
|
||||
|
||||
future.work(sysinv.kube_upgrade_start,
|
||||
self._platform_token,
|
||||
to_version,
|
||||
force=force,
|
||||
alarm_ignore_list=alarm_ignore_list)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete():
|
||||
DLOG.error("SysInv kube-upgrade-start did not complete.")
|
||||
response['reason'] = "did not complete."
|
||||
return
|
||||
|
||||
future.work(sysinv.get_kube_upgrade, self._platform_token)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete():
|
||||
DLOG.error("SysInv get-kube-upgrade did not complete.")
|
||||
response['reason'] = "did not complete."
|
||||
return
|
||||
|
||||
kube_upgrade_data_list = future.result.data['kube_upgrades']
|
||||
kube_upgrade_obj = \
|
||||
self._extract_kube_upgrade(kube_upgrade_data_list)
|
||||
response['result-data'] = kube_upgrade_obj
|
||||
response['completed'] = True
|
||||
|
||||
except exceptions.OpenStackRestAPIException as e:
|
||||
if httplib.UNAUTHORIZED == e.http_status_code:
|
||||
response['error-code'] = nfvi.NFVI_ERROR_CODE.TOKEN_EXPIRED
|
||||
if self._platform_token is not None:
|
||||
self._platform_token.set_expired()
|
||||
|
||||
else:
|
||||
DLOG.exception("Caught API exception while trying %s. error=%s"
|
||||
% (action_type, e))
|
||||
response['reason'] = e.http_response_reason
|
||||
|
||||
except Exception as e:
|
||||
DLOG.exception("Caught exception while trying %s. error=%s"
|
||||
% (action_type, e))
|
||||
|
||||
finally:
|
||||
callback.send(response)
|
||||
callback.close()
|
||||
|
||||
def get_upgrade(self, future, callback):
|
||||
"""
|
||||
Get information about the upgrade from the plugin
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2016-2018 Wind River Systems, Inc.
|
||||
# Copyright (c) 2016-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -216,6 +216,74 @@ class NFVISwMgmtAPI(nfvi.api.v1.NFVISwMgmtAPI):
|
|||
callback.send(response)
|
||||
callback.close()
|
||||
|
||||
def apply_patches(self, future, patch_names, callback):
|
||||
"""
|
||||
Apply a software patch that has already been uploaded
|
||||
"""
|
||||
response = dict()
|
||||
response['completed'] = False
|
||||
response['reason'] = ''
|
||||
|
||||
try:
|
||||
future.set_timeouts(config.CONF.get('nfvi-timeouts', None))
|
||||
|
||||
if self._token is None or self._token.is_expired():
|
||||
future.work(openstack.get_token, self._directory)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete() or \
|
||||
future.result.data is None:
|
||||
return
|
||||
|
||||
self._token = future.result.data
|
||||
|
||||
for patch_name in patch_names:
|
||||
future.work(patching.apply_patch, self._token, patch_name)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete():
|
||||
return
|
||||
|
||||
# query the patches and return their state
|
||||
future.work(patching.query_patches, self._token)
|
||||
future.result = (yield)
|
||||
|
||||
if not future.result.is_complete():
|
||||
return
|
||||
|
||||
sw_patches = list()
|
||||
|
||||
if future.result.data is not None:
|
||||
sw_patch_data_list = future.result.data.get('pd', [])
|
||||
for sw_patch_name in sw_patch_data_list.keys():
|
||||
sw_patch_data = sw_patch_data_list[sw_patch_name]
|
||||
sw_patch = nfvi.objects.v1.SwPatch(
|
||||
sw_patch_name, sw_patch_data['sw_version'],
|
||||
sw_patch_data['repostate'], sw_patch_data['patchstate'])
|
||||
sw_patches.append(sw_patch)
|
||||
|
||||
response['result-data'] = sw_patches
|
||||
response['completed'] = True
|
||||
|
||||
except exceptions.OpenStackRestAPIException as e:
|
||||
if httplib.UNAUTHORIZED == e.http_status_code:
|
||||
response['error-code'] = nfvi.NFVI_ERROR_CODE.TOKEN_EXPIRED
|
||||
if self._token is not None:
|
||||
self._token.set_expired()
|
||||
|
||||
else:
|
||||
DLOG.exception("Caught exception while trying to apply "
|
||||
"software patches [%s], error=%s."
|
||||
% (patch_names, e))
|
||||
|
||||
except Exception as e:
|
||||
DLOG.exception("Caught exception while trying to apply "
|
||||
"software patches [%s], error=%s."
|
||||
% (patch_names, e))
|
||||
finally:
|
||||
callback.send(response)
|
||||
callback.close()
|
||||
|
||||
def update_hosts(self, future, host_names, callback):
|
||||
"""
|
||||
Apply a software update to a list of hosts
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2016-2018 Wind River Systems, Inc.
|
||||
# Copyright (c) 2016-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -39,6 +39,20 @@ def query_hosts(token):
|
|||
return response
|
||||
|
||||
|
||||
def apply_patch(token, patch_name):
|
||||
"""
|
||||
Asks Patch Controller to apply a patch that is already uploaded
|
||||
"""
|
||||
url = token.get_service_url(PLATFORM_SERVICE.PATCHING, strip_version=True)
|
||||
if url is None:
|
||||
raise ValueError("OpenStack Patching URL is invalid")
|
||||
|
||||
api_cmd = url + "/v1/apply/%s" % str(patch_name)
|
||||
|
||||
response = rest_api_request(token, "POST", api_cmd)
|
||||
return response
|
||||
|
||||
|
||||
def host_install_async(token, host_name):
|
||||
"""
|
||||
Asks Patch Controller to perform a software upgrade on a host
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#
|
||||
# Copyright (c) 2015-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
import copy
|
||||
import json
|
||||
from nfv_common import debug
|
||||
|
||||
|
@ -97,6 +98,211 @@ def get_host_labels(token, host_uuid):
|
|||
return response
|
||||
|
||||
|
||||
def get_kube_host_upgrades(token):
|
||||
"""
|
||||
Asks System Inventory for information about the kube host upgrades
|
||||
"""
|
||||
url = token.get_service_url(PLATFORM_SERVICE.SYSINV)
|
||||
if url is None:
|
||||
raise ValueError("OpenStack SysInv URL is invalid")
|
||||
|
||||
api_cmd = url + "/kube_host_upgrades"
|
||||
|
||||
response = rest_api_request(token, "GET", api_cmd,
|
||||
timeout_in_secs=REST_API_REQUEST_TIMEOUT)
|
||||
return response
|
||||
|
||||
|
||||
def get_kube_upgrade(token):
|
||||
"""
|
||||
Asks System Inventory for information about the kube upgrade
|
||||
"""
|
||||
url = token.get_service_url(PLATFORM_SERVICE.SYSINV)
|
||||
if url is None:
|
||||
raise ValueError("OpenStack SysInv URL is invalid")
|
||||
|
||||
api_cmd = url + "/kube_upgrade"
|
||||
|
||||
response = rest_api_request(token, "GET", api_cmd,
|
||||
timeout_in_secs=REST_API_REQUEST_TIMEOUT)
|
||||
return response
|
||||
|
||||
|
||||
def get_kube_version(token, kube_version):
|
||||
"""
|
||||
Asks System Inventory for information a kube version
|
||||
"""
|
||||
url = token.get_service_url(PLATFORM_SERVICE.SYSINV)
|
||||
if url is None:
|
||||
raise ValueError("OpenStack SysInv URL is invalid")
|
||||
|
||||
api_cmd = url + "/kube_versions/" + kube_version
|
||||
|
||||
response = rest_api_request(token, "GET", api_cmd,
|
||||
timeout_in_secs=REST_API_REQUEST_TIMEOUT)
|
||||
return response
|
||||
|
||||
|
||||
def get_kube_versions(token):
|
||||
"""
|
||||
Asks System Inventory for information about the kube versions
|
||||
"""
|
||||
url = token.get_service_url(PLATFORM_SERVICE.SYSINV)
|
||||
if url is None:
|
||||
raise ValueError("OpenStack SysInv URL is invalid")
|
||||
|
||||
api_cmd = url + "/kube_versions"
|
||||
|
||||
response = rest_api_request(token, "GET", api_cmd,
|
||||
timeout_in_secs=REST_API_REQUEST_TIMEOUT)
|
||||
return response
|
||||
|
||||
|
||||
def kube_upgrade_start(token, to_version, force=False, alarm_ignore_list=None):
|
||||
"""
|
||||
Ask System Inventory to start a kube upgrade
|
||||
"""
|
||||
url = token.get_service_url(PLATFORM_SERVICE.SYSINV)
|
||||
if url is None:
|
||||
raise ValueError("OpenStack SysInv URL is invalid")
|
||||
|
||||
api_cmd = url + "/kube_upgrade"
|
||||
|
||||
api_cmd_headers = dict()
|
||||
api_cmd_headers['Content-Type'] = "application/json"
|
||||
api_cmd_headers['User-Agent'] = "vim/1.0"
|
||||
|
||||
api_cmd_payload = dict()
|
||||
api_cmd_payload['to_version'] = to_version
|
||||
api_cmd_payload['force'] = force
|
||||
if alarm_ignore_list is not None:
|
||||
api_cmd_payload['alarm_ignore_list'] = copy.copy(alarm_ignore_list)
|
||||
|
||||
response = rest_api_request(token,
|
||||
"POST",
|
||||
api_cmd,
|
||||
api_cmd_headers,
|
||||
json.dumps(api_cmd_payload),
|
||||
timeout_in_secs=REST_API_REQUEST_TIMEOUT)
|
||||
return response
|
||||
|
||||
|
||||
def _patch_kube_upgrade_state(token, new_value):
|
||||
url = token.get_service_url(PLATFORM_SERVICE.SYSINV)
|
||||
if url is None:
|
||||
raise ValueError("OpenStack SysInv URL is invalid")
|
||||
|
||||
api_cmd = url + "/kube_upgrade"
|
||||
|
||||
api_cmd_headers = dict()
|
||||
api_cmd_headers['Content-Type'] = "application/json"
|
||||
api_cmd_headers['User-Agent'] = "vim/1.0"
|
||||
|
||||
api_cmd_payload = list()
|
||||
host_data = dict()
|
||||
host_data['path'] = "/state"
|
||||
host_data['value'] = new_value
|
||||
host_data['op'] = "replace"
|
||||
api_cmd_payload.append(host_data)
|
||||
|
||||
return rest_api_request(token,
|
||||
"PATCH",
|
||||
api_cmd,
|
||||
api_cmd_headers,
|
||||
json.dumps(api_cmd_payload),
|
||||
timeout_in_secs=REST_API_REQUEST_TIMEOUT)
|
||||
|
||||
|
||||
def kube_upgrade_cleanup(token):
|
||||
"""
|
||||
Ask System Inventory to delete the kube upgrade
|
||||
"""
|
||||
url = token.get_service_url(PLATFORM_SERVICE.SYSINV)
|
||||
if url is None:
|
||||
raise ValueError("OpenStack SysInv URL is invalid")
|
||||
|
||||
api_cmd = url + "/kube_upgrade"
|
||||
|
||||
api_cmd_headers = dict()
|
||||
api_cmd_headers['Content-Type'] = "application/json"
|
||||
api_cmd_headers['User-Agent'] = "vim/1.0"
|
||||
|
||||
response = rest_api_request(token, "DELETE", api_cmd, api_cmd_headers,
|
||||
timeout_in_secs=REST_API_REQUEST_TIMEOUT)
|
||||
return response
|
||||
|
||||
|
||||
def kube_upgrade_complete(token):
|
||||
"""
|
||||
Ask System Inventory to kube upgrade complete
|
||||
"""
|
||||
return _patch_kube_upgrade_state(token, "upgrade-complete")
|
||||
|
||||
|
||||
def kube_upgrade_download_images(token):
|
||||
"""
|
||||
Ask System Inventory to kube upgrade download images
|
||||
"""
|
||||
return _patch_kube_upgrade_state(token, "downloading-images")
|
||||
|
||||
|
||||
def kube_upgrade_networking(token):
|
||||
"""
|
||||
Ask System Inventory to kube upgrade networking
|
||||
"""
|
||||
return _patch_kube_upgrade_state(token, "upgrading-networking")
|
||||
|
||||
|
||||
def _kube_host_upgrade(token, host_uuid, target_operation, force):
|
||||
"""
|
||||
Invoke a POST for a host kube-upgrade operation
|
||||
|
||||
target_operation one of: kube_upgrade_control_plane, kube_upgrade_kubelet
|
||||
force is a 'string'
|
||||
"""
|
||||
|
||||
url = token.get_service_url(PLATFORM_SERVICE.SYSINV)
|
||||
if url is None:
|
||||
raise ValueError("OpenStack SysInv URL is invalid")
|
||||
|
||||
api_cmd = url + "/ihosts/%s/%s" % (host_uuid, target_operation)
|
||||
|
||||
api_cmd_headers = dict()
|
||||
api_cmd_headers['Content-Type'] = "application/json"
|
||||
api_cmd_headers['User-Agent'] = "vim/1.0"
|
||||
|
||||
api_cmd_payload = dict()
|
||||
api_cmd_payload['force'] = force
|
||||
|
||||
response = rest_api_request(token,
|
||||
"POST",
|
||||
api_cmd,
|
||||
api_cmd_headers,
|
||||
json.dumps(api_cmd_payload),
|
||||
timeout_in_secs=REST_API_REQUEST_TIMEOUT)
|
||||
return response
|
||||
|
||||
|
||||
def kube_host_upgrade_control_plane(token, host_uuid, force="true"):
|
||||
"""
|
||||
Ask System Inventory to kube HOST upgrade control plane
|
||||
"""
|
||||
return _kube_host_upgrade(token,
|
||||
host_uuid,
|
||||
"kube_upgrade_control_plane",
|
||||
force)
|
||||
|
||||
|
||||
def kube_host_upgrade_kubelet(token, host_uuid, force="true"):
|
||||
"""
|
||||
Ask System Inventory to kube HOST upgrade kubelet
|
||||
"""
|
||||
return _kube_host_upgrade(token,
|
||||
host_uuid,
|
||||
"kube_upgrade_kubelet",
|
||||
force)
|
||||
|
||||
|
||||
def get_upgrade(token):
|
||||
"""
|
||||
Asks System Inventory for information about the upgrade
|
||||
|
|
|
@ -0,0 +1,734 @@
|
|||
#
|
||||
# Copyright (c) 2020-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
import mock
|
||||
import uuid
|
||||
|
||||
from nfv_common import strategy as common_strategy
|
||||
from nfv_vim import nfvi
|
||||
|
||||
from nfv_vim.nfvi.objects.v1 import HostSwPatch
|
||||
from nfv_vim.nfvi.objects.v1 import KUBE_UPGRADE_STATE
|
||||
from nfv_vim.nfvi.objects.v1 import KubeVersion
|
||||
from nfv_vim.nfvi.objects.v1 import SwPatch
|
||||
from nfv_vim.objects import KubeUpgrade
|
||||
from nfv_vim.objects import SW_UPDATE_ALARM_RESTRICTION
|
||||
from nfv_vim.objects import SW_UPDATE_APPLY_TYPE
|
||||
from nfv_vim.strategy._strategy import KubeUpgradeStrategy
|
||||
|
||||
from . import sw_update_testcase # noqa: H304
|
||||
|
||||
|
||||
FROM_KUBE_VERSION = '1.2.3'
|
||||
TO_KUBE_VERSION = '1.2.4'
|
||||
|
||||
FAKE_LOAD = '12.01'
|
||||
|
||||
KUBE_PATCH_1 = 'KUBE.1' # the control plane patch
|
||||
KUBE_PATCH_2 = 'KUBE.2' # the kubelet patch
|
||||
|
||||
|
||||
@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 TestBuildStrategy(sw_update_testcase.SwUpdateStrategyTestCase):
|
||||
|
||||
def _create_kube_upgrade_strategy(self,
|
||||
sw_update_obj,
|
||||
storage_apply_type=SW_UPDATE_APPLY_TYPE.SERIAL,
|
||||
worker_apply_type=SW_UPDATE_APPLY_TYPE.SERIAL,
|
||||
max_parallel_worker_hosts=10,
|
||||
alarm_restrictions=SW_UPDATE_ALARM_RESTRICTION.STRICT,
|
||||
to_version=TO_KUBE_VERSION,
|
||||
single_controller=False,
|
||||
nfvi_kube_upgrade=None):
|
||||
"""
|
||||
Create a kube upgrade strategy
|
||||
"""
|
||||
strategy = KubeUpgradeStrategy(
|
||||
uuid=str(uuid.uuid4()),
|
||||
storage_apply_type=storage_apply_type,
|
||||
worker_apply_type=worker_apply_type,
|
||||
max_parallel_worker_hosts=max_parallel_worker_hosts,
|
||||
alarm_restrictions=alarm_restrictions,
|
||||
ignore_alarms=[],
|
||||
to_version=to_version,
|
||||
single_controller=single_controller
|
||||
)
|
||||
strategy.sw_update_obj = sw_update_obj # this is a weakref
|
||||
strategy.nfvi_kube_upgrade = nfvi_kube_upgrade
|
||||
return strategy
|
||||
|
||||
@mock.patch('nfv_common.strategy._strategy.Strategy._build')
|
||||
def test_kube_upgrade_strategy_build_steps(self, fake_build):
|
||||
"""
|
||||
Verify build phase steps and stages for kube_upgrade strategy creation.
|
||||
"""
|
||||
# setup a minimal host environment
|
||||
self.create_host('controller-0')
|
||||
|
||||
# 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 = KubeUpgrade()
|
||||
strategy = self._create_kube_upgrade_strategy(update_obj,
|
||||
single_controller=True)
|
||||
# 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-kube-versions'},
|
||||
{'name': 'query-kube-upgrade'},
|
||||
{'name': 'query-kube-host-upgrade'},
|
||||
{'name': 'query-sw-patches'},
|
||||
{'name': 'query-sw-patch-hosts'},
|
||||
]
|
||||
expected_results = {
|
||||
'total_stages': 1,
|
||||
'stages': [
|
||||
{'name': 'kube-upgrade-query',
|
||||
'total_steps': len(query_steps),
|
||||
'steps': query_steps,
|
||||
},
|
||||
],
|
||||
}
|
||||
sw_update_testcase.validate_phase(build_phase, expected_results)
|
||||
|
||||
|
||||
class SimplexKubeUpgradeMixin(object):
|
||||
FAKE_PATCH_HOSTS_LIST = [
|
||||
HostSwPatch('controller-0', 'controller', FAKE_LOAD,
|
||||
True, False, 'idle', False, False),
|
||||
]
|
||||
FAKE_KUBE_HOST_UPGRADES_LIST = []
|
||||
|
||||
def setUp(self):
|
||||
super(SimplexKubeUpgradeMixin, self).setUp()
|
||||
|
||||
def is_simplex(self):
|
||||
return True
|
||||
|
||||
def is_duplex(self):
|
||||
return False
|
||||
|
||||
def _kube_upgrade_kubelet_controller_stage(self, host):
|
||||
"""duplex needs to swact/lock/unlock whereas simplex does not"""
|
||||
steps = [
|
||||
{'name': 'kube-host-upgrade-kubelet',
|
||||
'entity_names': [host],
|
||||
'entity_type': 'hosts', },
|
||||
{'name': 'system-stabilize', },
|
||||
]
|
||||
|
||||
return {
|
||||
'name': 'kube-upgrade-kubelets-controllers',
|
||||
'total_steps': len(steps),
|
||||
'steps': steps,
|
||||
}
|
||||
|
||||
|
||||
class DuplexKubeUpgradeMixin(object):
|
||||
FAKE_PATCH_HOSTS_LIST = [
|
||||
HostSwPatch('controller-0', 'controller', FAKE_LOAD,
|
||||
True, False, 'idle', False, False),
|
||||
HostSwPatch('controller-1', 'controller', FAKE_LOAD,
|
||||
True, False, 'idle', False, False),
|
||||
]
|
||||
FAKE_KUBE_HOST_UPGRADES_LIST = []
|
||||
|
||||
def setUp(self):
|
||||
super(DuplexKubeUpgradeMixin, self).setUp()
|
||||
|
||||
def is_simplex(self):
|
||||
return False
|
||||
|
||||
def is_duplex(self):
|
||||
return True
|
||||
|
||||
def _kube_upgrade_kubelet_controller_stage(self, host):
|
||||
"""duplex needs to swact/lock/unlock whereas simplex does not"""
|
||||
steps = [
|
||||
{'name': 'swact-hosts',
|
||||
'entity_names': [host],
|
||||
'entity_type': 'hosts', },
|
||||
{'name': 'lock-hosts',
|
||||
'entity_names': [host],
|
||||
'entity_type': 'hosts', },
|
||||
{'name': 'kube-host-upgrade-kubelet',
|
||||
'entity_names': [host],
|
||||
'entity_type': 'hosts', },
|
||||
{'name': 'system-stabilize', },
|
||||
{'name': 'unlock-hosts',
|
||||
'entity_names': [host],
|
||||
'entity_type': 'hosts', },
|
||||
{'name': 'wait-alarms-clear', },
|
||||
]
|
||||
return {
|
||||
'name': 'kube-upgrade-kubelets-controllers',
|
||||
'total_steps': len(steps),
|
||||
'steps': steps,
|
||||
}
|
||||
|
||||
|
||||
class KubePatchMixin(object):
|
||||
"""This Mixin represents the patches for a kube upgrade in proper state"""
|
||||
|
||||
FAKE_KUBE_VERSIONS_LIST = [
|
||||
KubeVersion(
|
||||
FROM_KUBE_VERSION, # kube_version
|
||||
'active', # state
|
||||
True, # target
|
||||
[], # upgrade_from
|
||||
[], # downgrade_to
|
||||
[], # applied_patches
|
||||
[] # available_patches
|
||||
),
|
||||
KubeVersion(
|
||||
TO_KUBE_VERSION, # kube_version
|
||||
'available', # state
|
||||
False, # target
|
||||
[FROM_KUBE_VERSION], # upgrade_from
|
||||
[], # downgrade_to
|
||||
[KUBE_PATCH_1], # applied_patches
|
||||
[KUBE_PATCH_2] # available_patches
|
||||
)
|
||||
]
|
||||
|
||||
FAKE_PATCHES_LIST = [
|
||||
SwPatch(KUBE_PATCH_1, FAKE_LOAD, 'Applied', 'Applied'),
|
||||
SwPatch(KUBE_PATCH_2, FAKE_LOAD, 'Available', 'Available'),
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super(KubePatchMixin, self).setUp()
|
||||
|
||||
def _kube_upgrade_patch_stage(self,
|
||||
controller_list,
|
||||
storage_list=None,
|
||||
worker_list=None):
|
||||
"""hosts are patched in the following order
|
||||
controller-0 in simplex,
|
||||
controller-1, controller-0 for duplex
|
||||
storage hosts after controllers
|
||||
workers after storage hosts
|
||||
"""
|
||||
if storage_list is None:
|
||||
storage_list = []
|
||||
if worker_list is None:
|
||||
worker_list = []
|
||||
patch_steps = [
|
||||
{'name': 'apply-patches',
|
||||
'entity_type': 'patches',
|
||||
'entity_names': ['KUBE.2']}
|
||||
]
|
||||
for host_name in controller_list:
|
||||
patch_steps.append({'name': 'sw-patch-hosts',
|
||||
'entity_type': 'hosts',
|
||||
'entity_names': [host_name]})
|
||||
# storage and workers may be processed in bulk in the future
|
||||
for host_name in storage_list:
|
||||
patch_steps.append({'name': 'sw-patch-hosts',
|
||||
'entity_type': 'hosts',
|
||||
'entity_names': [host_name]})
|
||||
for host_name in worker_list:
|
||||
patch_steps.append({'name': 'sw-patch-hosts',
|
||||
'entity_type': 'hosts',
|
||||
'entity_names': [host_name]})
|
||||
return {
|
||||
'name': 'kube-upgrade-patch',
|
||||
'total_steps': len(patch_steps),
|
||||
'steps': patch_steps
|
||||
}
|
||||
|
||||
|
||||
class ApplyStageMixin(object):
|
||||
"""This Mixin will not work unless combined with other mixins.
|
||||
PatchMixin - to provide the setup patches and kube versions
|
||||
HostMixin - to provide the patch hosts and kube host upgrade states
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(ApplyStageMixin, self).setUp()
|
||||
|
||||
def _create_kube_upgrade_obj(self,
|
||||
state,
|
||||
from_version=FROM_KUBE_VERSION,
|
||||
to_version=TO_KUBE_VERSION):
|
||||
"""
|
||||
Create a kube upgrade db object
|
||||
"""
|
||||
return nfvi.objects.v1.KubeUpgrade(state=state,
|
||||
from_version=from_version,
|
||||
to_version=to_version)
|
||||
|
||||
def _create_built_kube_upgrade_strategy(self,
|
||||
sw_update_obj,
|
||||
to_version=TO_KUBE_VERSION,
|
||||
single_controller=False,
|
||||
kube_upgrade=None,
|
||||
alarms_list=None,
|
||||
patch_list=None,
|
||||
patch_hosts_list=None,
|
||||
kube_versions_list=None,
|
||||
kube_hosts_list=None):
|
||||
"""
|
||||
Create a kube upgrade strategy
|
||||
populate the API query results from the build steps
|
||||
"""
|
||||
storage_apply_type = SW_UPDATE_APPLY_TYPE.IGNORE
|
||||
worker_apply_type = SW_UPDATE_APPLY_TYPE.IGNORE
|
||||
max_parallel_worker_hosts = 10
|
||||
alarm_restrictions = SW_UPDATE_ALARM_RESTRICTION.STRICT
|
||||
|
||||
strategy = KubeUpgradeStrategy(
|
||||
uuid=str(uuid.uuid4()),
|
||||
storage_apply_type=storage_apply_type,
|
||||
worker_apply_type=worker_apply_type,
|
||||
max_parallel_worker_hosts=max_parallel_worker_hosts,
|
||||
alarm_restrictions=alarm_restrictions,
|
||||
ignore_alarms=[],
|
||||
to_version=to_version,
|
||||
single_controller=single_controller
|
||||
)
|
||||
strategy.sw_update_obj = sw_update_obj # warning: this is a weakref
|
||||
strategy.nfvi_kube_upgrade = kube_upgrade
|
||||
|
||||
# If any of the input lists are None, replace with defaults
|
||||
# this is done to prevent passing a list as a default
|
||||
if patch_list is None:
|
||||
patch_list = self.FAKE_PATCHES_LIST
|
||||
strategy.nfvi_sw_patches = patch_list
|
||||
|
||||
if patch_hosts_list is None:
|
||||
patch_hosts_list = self.FAKE_PATCH_HOSTS_LIST
|
||||
strategy.nfvi_sw_patch_hosts = patch_hosts_list
|
||||
|
||||
if kube_versions_list is None:
|
||||
kube_versions_list = self.FAKE_KUBE_VERSIONS_LIST
|
||||
strategy.nfvi_kube_versions_list = kube_versions_list
|
||||
|
||||
if kube_hosts_list is None:
|
||||
kube_hosts_list = self.FAKE_KUBE_HOST_UPGRADES_LIST
|
||||
strategy.nfvi_kube_host_upgrade_list = kube_hosts_list
|
||||
|
||||
return strategy
|
||||
|
||||
def _kube_upgrade_start_stage(self):
|
||||
return {
|
||||
'name': 'kube-upgrade-start',
|
||||
'total_steps': 1,
|
||||
'steps': [
|
||||
{'name': 'kube-upgrade-start',
|
||||
'success_state': 'upgrade-started'},
|
||||
],
|
||||
}
|
||||
|
||||
def _kube_upgrade_download_images_stage(self):
|
||||
return {
|
||||
'name': 'kube-upgrade-download-images',
|
||||
'total_steps': 1,
|
||||
'steps': [
|
||||
{'name': 'kube-upgrade-download-images',
|
||||
'success_state': 'downloaded-images',
|
||||
'fail_state': 'downloading-images-failed'},
|
||||
],
|
||||
}
|
||||
|
||||
def _kube_upgrade_first_control_plane_stage(self):
|
||||
return {
|
||||
'name': 'kube-upgrade-first-control-plane',
|
||||
'total_steps': 1,
|
||||
'steps': [
|
||||
{'name': 'kube-host-upgrade-control-plane',
|
||||
'success_state': 'upgraded-first-master',
|
||||
'fail_state': 'upgrading-first-master-failed'},
|
||||
],
|
||||
}
|
||||
|
||||
def _kube_upgrade_networking_stage(self):
|
||||
return {
|
||||
'name': 'kube-upgrade-networking',
|
||||
'total_steps': 1,
|
||||
'steps': [
|
||||
{'name': 'kube-upgrade-networking',
|
||||
'success_state': 'upgraded-networking',
|
||||
'fail_state': 'upgrading-networking-failed'},
|
||||
],
|
||||
}
|
||||
|
||||
def _kube_upgrade_second_control_plane_stage(self):
|
||||
"""This stage only executes on a duplex system"""
|
||||
return {
|
||||
'name': 'kube-upgrade-second-control-plane',
|
||||
'total_steps': 1,
|
||||
'steps': [
|
||||
{'name': 'kube-host-upgrade-control-plane',
|
||||
'success_state': 'upgraded-second-master',
|
||||
'fail_state': 'upgrading-second-master-failed'},
|
||||
],
|
||||
}
|
||||
|
||||
def _kube_upgrade_complete_stage(self):
|
||||
return {
|
||||
'name': 'kube-upgrade-complete',
|
||||
'total_steps': 1,
|
||||
'steps': [
|
||||
{'name': 'kube-upgrade-complete',
|
||||
'success_state': 'upgrade-complete'},
|
||||
],
|
||||
}
|
||||
|
||||
def _kube_upgrade_cleanup_stage(self):
|
||||
return {
|
||||
'name': 'kube-upgrade-cleanup',
|
||||
'total_steps': 1,
|
||||
'steps': [
|
||||
{'name': 'kube-upgrade-cleanup'},
|
||||
],
|
||||
}
|
||||
|
||||
def _kube_upgrade_kubelet_worker_stage(self, host):
|
||||
steps = [
|
||||
{'name': 'lock-hosts',
|
||||
'entity_names': [host], },
|
||||
{'name': 'kube-host-upgrade-kubelet',
|
||||
'entity_names': [host],
|
||||
'entity_type': 'hosts', },
|
||||
{'name': 'system-stabilize', },
|
||||
{'name': 'unlock-hosts',
|
||||
'entity_names': [host],
|
||||
'entity_type': 'hosts', },
|
||||
{'name': 'wait-alarms-clear', },
|
||||
]
|
||||
return {
|
||||
'name': 'kube-upgrade-kubelets-workers',
|
||||
'total_steps': len(steps),
|
||||
'steps': steps,
|
||||
}
|
||||
|
||||
def _kube_upgrade_kubelet_stages(self, controller_list, worker_list=None):
|
||||
"""This section will change as more host types are supported"""
|
||||
if worker_list is None:
|
||||
worker_list = []
|
||||
kubelet_stages = []
|
||||
for host_name in controller_list:
|
||||
kubelet_stages.append(
|
||||
self._kube_upgrade_kubelet_controller_stage(host_name))
|
||||
for host_name in worker_list:
|
||||
kubelet_stages.append(
|
||||
self._kube_upgrade_kubelet_worker_stage(host_name))
|
||||
return kubelet_stages
|
||||
|
||||
def validate_apply_phase(self, single_controller, kube_upgrade, stages):
|
||||
# sw_update_obj is a weak ref. it must be defined here
|
||||
update_obj = KubeUpgrade()
|
||||
|
||||
# create a strategy for a system with no existing kube_upgrade
|
||||
strategy = self._create_built_kube_upgrade_strategy(
|
||||
update_obj,
|
||||
single_controller=single_controller,
|
||||
kube_upgrade=kube_upgrade)
|
||||
|
||||
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': len(stages),
|
||||
'stages': stages
|
||||
}
|
||||
sw_update_testcase.validate_strategy_persists(strategy)
|
||||
sw_update_testcase.validate_phase(apply_phase, expected_results)
|
||||
|
||||
def build_stage_list(self,
|
||||
controller_list,
|
||||
worker_list,
|
||||
add_start=True, add_download=True,
|
||||
add_first_plane=True, add_networking=True,
|
||||
add_second_plane=True, add_patches=True,
|
||||
add_kubelets=True,
|
||||
add_complete=True, add_cleanup=True):
|
||||
"""The order of the host_list determines the patch and kubelets"""
|
||||
stages = []
|
||||
if add_start:
|
||||
stages.append(self._kube_upgrade_start_stage())
|
||||
if add_download:
|
||||
stages.append(self._kube_upgrade_download_images_stage())
|
||||
if add_first_plane:
|
||||
stages.append(self._kube_upgrade_first_control_plane_stage())
|
||||
if add_networking:
|
||||
stages.append(self._kube_upgrade_networking_stage())
|
||||
if add_second_plane:
|
||||
stages.append(self._kube_upgrade_second_control_plane_stage())
|
||||
if add_patches:
|
||||
stages.append(self._kube_upgrade_patch_stage(controller_list,
|
||||
worker_list))
|
||||
if add_kubelets:
|
||||
stages.extend(self._kube_upgrade_kubelet_stages(controller_list,
|
||||
worker_list))
|
||||
if add_complete:
|
||||
stages.append(self._kube_upgrade_complete_stage())
|
||||
if add_cleanup:
|
||||
stages.append(self._kube_upgrade_cleanup_stage())
|
||||
return stages
|
||||
|
||||
def test_no_existing_upgrade(self):
|
||||
"""
|
||||
Test the kube_upgrade strategy creation for the hosts when there is
|
||||
no existing kube upgrade exists.
|
||||
A duplex env will have more steps than a simplex environment
|
||||
"""
|
||||
kube_upgrade = None
|
||||
# default stage list includes all , however second plane is duplex only
|
||||
stages = self.build_stage_list(self.controller_list,
|
||||
self.worker_list,
|
||||
add_second_plane=self.is_duplex())
|
||||
self.validate_apply_phase(self.is_simplex(), kube_upgrade, stages)
|
||||
|
||||
def test_resume_after_upgrade_started(self):
|
||||
"""
|
||||
Test the kube_upgrade strategy creation when the upgrade was created
|
||||
already (upgrade-started)
|
||||
The 'start stage should be skipped and the upgrade resumes at the
|
||||
'downloading images' stage
|
||||
"""
|
||||
kube_upgrade = self._create_kube_upgrade_obj(
|
||||
KUBE_UPGRADE_STATE.KUBE_UPGRADE_STARTED)
|
||||
# explicity bypass the start stage
|
||||
stages = self.build_stage_list(self.controller_list,
|
||||
self.worker_list,
|
||||
add_start=False,
|
||||
add_second_plane=self.is_duplex())
|
||||
self.validate_apply_phase(self.is_simplex(), kube_upgrade, stages)
|
||||
|
||||
def test_resume_after_upgrade_complete(self):
|
||||
"""
|
||||
Test the kube_upgrade strategy creation when the upgrade had previously
|
||||
stopped after upgrade-completed.
|
||||
It is expected to resume at the cleanup stage
|
||||
"""
|
||||
kube_upgrade = self._create_kube_upgrade_obj(
|
||||
KUBE_UPGRADE_STATE.KUBE_UPGRADE_COMPLETE)
|
||||
# not using build_stage_list utility since the list of stages is small
|
||||
stages = [
|
||||
self._kube_upgrade_cleanup_stage(),
|
||||
]
|
||||
self.validate_apply_phase(self.is_simplex(), kube_upgrade, stages)
|
||||
|
||||
|
||||
@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 TestSimplexApplyStrategy(sw_update_testcase.SwUpdateStrategyTestCase,
|
||||
KubePatchMixin,
|
||||
ApplyStageMixin,
|
||||
SimplexKubeUpgradeMixin):
|
||||
def setUp(self):
|
||||
super(TestSimplexApplyStrategy, self).setUp()
|
||||
self.create_host('controller-0')
|
||||
self.controller_list = ['controller-0', ]
|
||||
self.worker_list = []
|
||||
|
||||
def test_resume_after_download_images_failed(self):
|
||||
"""
|
||||
Test the kube_upgrade strategy creation when the upgrade had previously
|
||||
stopped with 'downloading-images-failed'
|
||||
It is expected to resume at the 'downloading images' stage
|
||||
"""
|
||||
kube_upgrade = self._create_kube_upgrade_obj(
|
||||
KUBE_UPGRADE_STATE.KUBE_UPGRADE_DOWNLOADING_IMAGES_FAILED)
|
||||
stages = [
|
||||
self._kube_upgrade_download_images_stage(),
|
||||
self._kube_upgrade_first_control_plane_stage(),
|
||||
self._kube_upgrade_networking_stage(),
|
||||
self._kube_upgrade_patch_stage(['controller-0']),
|
||||
self._kube_upgrade_kubelet_controller_stage('controller-0'),
|
||||
self._kube_upgrade_complete_stage(),
|
||||
self._kube_upgrade_cleanup_stage(),
|
||||
]
|
||||
self.validate_apply_phase(self.is_simplex(), kube_upgrade, stages)
|
||||
|
||||
def test_resume_after_download_images_succeeded(self):
|
||||
"""
|
||||
Test the kube_upgrade strategy creation when the upgrade had previously
|
||||
stopped with 'downloaded-images'
|
||||
It is expected to resume at the 'first control plane' stage.
|
||||
"""
|
||||
kube_upgrade = self._create_kube_upgrade_obj(
|
||||
KUBE_UPGRADE_STATE.KUBE_UPGRADE_DOWNLOADED_IMAGES)
|
||||
stages = [
|
||||
self._kube_upgrade_first_control_plane_stage(),
|
||||
self._kube_upgrade_networking_stage(),
|
||||
self._kube_upgrade_patch_stage(['controller-0']),
|
||||
self._kube_upgrade_kubelet_controller_stage('controller-0'),
|
||||
self._kube_upgrade_complete_stage(),
|
||||
self._kube_upgrade_cleanup_stage(),
|
||||
]
|
||||
self.validate_apply_phase(self.is_simplex(), kube_upgrade, stages)
|
||||
|
||||
def test_resume_after_first_control_plane_failed(self):
|
||||
"""
|
||||
Test the kube_upgrade strategy creation when there is only a simplex
|
||||
and the upgrade had previously failed during the first control plane.
|
||||
It is expected to resume and retry the 'first control plane' stage
|
||||
"""
|
||||
kube_upgrade = self._create_kube_upgrade_obj(
|
||||
KUBE_UPGRADE_STATE.KUBE_UPGRADING_FIRST_MASTER_FAILED)
|
||||
stages = [
|
||||
self._kube_upgrade_first_control_plane_stage(),
|
||||
self._kube_upgrade_networking_stage(),
|
||||
self._kube_upgrade_patch_stage(['controller-0']),
|
||||
self._kube_upgrade_kubelet_controller_stage('controller-0'),
|
||||
self._kube_upgrade_complete_stage(),
|
||||
self._kube_upgrade_cleanup_stage(),
|
||||
]
|
||||
self.validate_apply_phase(self.is_simplex(), kube_upgrade, stages)
|
||||
|
||||
def test_resume_after_first_control_plane_succeeded(self):
|
||||
"""
|
||||
Test the kube_upgrade strategy creation when there is only a simplex
|
||||
and the upgrade had previously stopped after the first control plane.
|
||||
It is expected to resume at the networking stage
|
||||
"""
|
||||
kube_upgrade = self._create_kube_upgrade_obj(
|
||||
KUBE_UPGRADE_STATE.KUBE_UPGRADED_FIRST_MASTER)
|
||||
stages = [
|
||||
self._kube_upgrade_networking_stage(),
|
||||
self._kube_upgrade_patch_stage(['controller-0']),
|
||||
self._kube_upgrade_kubelet_controller_stage('controller-0'),
|
||||
self._kube_upgrade_complete_stage(),
|
||||
self._kube_upgrade_cleanup_stage(),
|
||||
]
|
||||
self.validate_apply_phase(self.is_simplex(), kube_upgrade, stages)
|
||||
|
||||
def test_resume_after_networking_failed(self):
|
||||
"""
|
||||
Test the kube_upgrade strategy creation when there is only a simplex
|
||||
and the upgrade had previously failed during networking.
|
||||
It is expected to retry and resume at the networking stage
|
||||
"""
|
||||
kube_upgrade = self._create_kube_upgrade_obj(
|
||||
KUBE_UPGRADE_STATE.KUBE_UPGRADING_NETWORKING_FAILED)
|
||||
stages = [
|
||||
self._kube_upgrade_networking_stage(),
|
||||
self._kube_upgrade_patch_stage(['controller-0']),
|
||||
self._kube_upgrade_kubelet_controller_stage('controller-0'),
|
||||
self._kube_upgrade_complete_stage(),
|
||||
self._kube_upgrade_cleanup_stage(),
|
||||
]
|
||||
self.validate_apply_phase(self.is_simplex(), kube_upgrade, stages)
|
||||
|
||||
def test_resume_after_networking_succeeded(self):
|
||||
"""
|
||||
Test the kube_upgrade strategy creation when there is only a simplex
|
||||
and the upgrade had previously stopped after successful networking.
|
||||
It is expected to resume at the patch stage
|
||||
"""
|
||||
kube_upgrade = self._create_kube_upgrade_obj(
|
||||
KUBE_UPGRADE_STATE.KUBE_UPGRADED_NETWORKING)
|
||||
stages = [
|
||||
self._kube_upgrade_patch_stage(['controller-0']),
|
||||
self._kube_upgrade_kubelet_controller_stage('controller-0'),
|
||||
self._kube_upgrade_complete_stage(),
|
||||
self._kube_upgrade_cleanup_stage(),
|
||||
]
|
||||
self.validate_apply_phase(self.is_simplex(), kube_upgrade, stages)
|
||||
|
||||
def test_resume_after_invalid_second_master_state(self):
|
||||
"""
|
||||
Test the kube_upgrade strategy creation when there is only a simplex
|
||||
and the upgrade had previously stopped after a second control plane
|
||||
state is encountered.
|
||||
There should never be a second control plane state in a simplex, so
|
||||
the stages should skip over it to the patch stage.
|
||||
"""
|
||||
kube_upgrade = self._create_kube_upgrade_obj(
|
||||
KUBE_UPGRADE_STATE.KUBE_UPGRADED_SECOND_MASTER)
|
||||
stages = [
|
||||
self._kube_upgrade_patch_stage(['controller-0']),
|
||||
self._kube_upgrade_kubelet_controller_stage('controller-0'),
|
||||
self._kube_upgrade_complete_stage(),
|
||||
self._kube_upgrade_cleanup_stage(),
|
||||
]
|
||||
self.validate_apply_phase(self.is_simplex(), kube_upgrade, stages)
|
||||
|
||||
def test_resume_after_invalid_second_master_fail_state(self):
|
||||
"""
|
||||
Test the kube_upgrade strategy creation when there is only a simplex
|
||||
and the upgrade had previously stopped after a second control plane
|
||||
failure state is encountered.
|
||||
There should never be a second control plane state in a simplex, so
|
||||
the stages should skip over it to the patch stage.
|
||||
"""
|
||||
kube_upgrade = self._create_kube_upgrade_obj(
|
||||
KUBE_UPGRADE_STATE.KUBE_UPGRADING_SECOND_MASTER_FAILED)
|
||||
stages = [
|
||||
self._kube_upgrade_patch_stage(['controller-0']),
|
||||
self._kube_upgrade_kubelet_controller_stage('controller-0'),
|
||||
self._kube_upgrade_complete_stage(),
|
||||
self._kube_upgrade_cleanup_stage(),
|
||||
]
|
||||
self.validate_apply_phase(self.is_simplex(), kube_upgrade, stages)
|
||||
|
||||
|
||||
@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 TestDuplexApplyStrategy(sw_update_testcase.SwUpdateStrategyTestCase,
|
||||
KubePatchMixin,
|
||||
ApplyStageMixin,
|
||||
DuplexKubeUpgradeMixin):
|
||||
def setUp(self):
|
||||
super(TestDuplexApplyStrategy, self).setUp()
|
||||
self.create_host('controller-0')
|
||||
self.create_host('controller-1')
|
||||
# the order in which hosts should be patched
|
||||
self.controller_list = ['controller-1', 'controller-0']
|
||||
self.worker_list = []
|
||||
|
||||
|
||||
@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 TestDuplexPlusApplyStrategy(sw_update_testcase.SwUpdateStrategyTestCase,
|
||||
KubePatchMixin,
|
||||
ApplyStageMixin,
|
||||
DuplexKubeUpgradeMixin):
|
||||
def setUp(self):
|
||||
super(TestDuplexPlusApplyStrategy, self).setUp()
|
||||
self.create_host('controller-0')
|
||||
self.create_host('controller-1')
|
||||
self.create_host('compute-0') # creates a worker
|
||||
# the order in which hosts should be patched
|
||||
self.controller_list = ['controller-1', 'controller-0']
|
||||
self.worker_list = ['compute-0']
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2016-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2016-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -114,6 +114,41 @@ _alarm_templates = {
|
|||
"problem persists contact next level of support"),
|
||||
'exclude_alarm_context': [alarm.ALARM_CONTEXT.TENANT],
|
||||
},
|
||||
|
||||
alarm.ALARM_TYPE.KUBE_UPGRADE_AUTO_APPLY_INPROGRESS: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'event_type': alarm.ALARM_EVENT_TYPE.EQUIPMENT_ALARM,
|
||||
'severity': alarm.ALARM_SEVERITY.MAJOR,
|
||||
'probable_cause': alarm.ALARM_PROBABLE_CAUSE.UNKNOWN,
|
||||
'reason_text': "Kubernetes upgrade auto-apply inprogress",
|
||||
'repair_action': ("Wait for kubernetes upgrade auto-apply to complete; "
|
||||
"if problem persists contact next level of support"),
|
||||
'exclude_alarm_context': [alarm.ALARM_CONTEXT.TENANT],
|
||||
},
|
||||
alarm.ALARM_TYPE.KUBE_UPGRADE_AUTO_APPLY_ABORTING: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'event_type': alarm.ALARM_EVENT_TYPE.EQUIPMENT_ALARM,
|
||||
'severity': alarm.ALARM_SEVERITY.MAJOR,
|
||||
'probable_cause': alarm.ALARM_PROBABLE_CAUSE.UNKNOWN,
|
||||
'reason_text': "Kubernetes upgrade auto-apply aborting",
|
||||
'repair_action': ("Wait for kubernetes upgrade auto-apply abort to "
|
||||
"complete; if problem persists contact next "
|
||||
"level of support"),
|
||||
'exclude_alarm_context': [alarm.ALARM_CONTEXT.TENANT],
|
||||
},
|
||||
alarm.ALARM_TYPE.KUBE_UPGRADE_AUTO_APPLY_FAILED: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'event_type': alarm.ALARM_EVENT_TYPE.EQUIPMENT_ALARM,
|
||||
'severity': alarm.ALARM_SEVERITY.CRITICAL,
|
||||
'probable_cause': alarm.ALARM_PROBABLE_CAUSE.UNKNOWN,
|
||||
'reason_text': "Kubernetes upgrade auto-apply failed",
|
||||
'repair_action': ("Attempt to apply kubernetes upgrade manually; if "
|
||||
"problem persists contact next level of support"),
|
||||
'exclude_alarm_context': [alarm.ALARM_CONTEXT.TENANT],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -11,6 +11,7 @@ import wsmeext.pecan as wsme_pecan
|
|||
|
||||
from nfv_vim.api._link import Link
|
||||
from nfv_vim.api.controllers.v1.orchestration.sw_update import FwUpdateAPI
|
||||
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
|
||||
|
||||
|
@ -32,6 +33,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('kube-upgrade',
|
||||
url, 'orchestration/kube-upgrade', ''),
|
||||
Link.make_link('fw-update', url, 'orchestration/fw-update', '')]
|
||||
return description
|
||||
|
||||
|
@ -48,6 +51,8 @@ class OrchestrationAPI(rest.RestController):
|
|||
return SwUpgradeAPI(), remainder
|
||||
elif 'fw-update' == key:
|
||||
return FwUpdateAPI(), remainder
|
||||
elif 'kube-upgrade' == key:
|
||||
return KubeUpgradeAPI(), remainder
|
||||
else:
|
||||
pecan.abort(httplib.NOT_FOUND)
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#
|
||||
# Copyright (c) 2015-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
from nfv_vim.api.controllers.v1.orchestration.sw_update._fw_update import FwUpdateAPI # noqa: F401
|
||||
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
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
#
|
||||
# Copyright (c) 2020-2021 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 KubeUpgradeStrategyAPI
|
||||
|
||||
DLOG = debug.debug_get_logger('nfv_vim.api.kube_upgrade')
|
||||
|
||||
|
||||
class KubeUpgradeDescription(wsme_types.Base):
|
||||
"""
|
||||
Kubernetes Update Description
|
||||
"""
|
||||
id = wsme_types.text
|
||||
links = wsme_types.wsattr([Link], name='links')
|
||||
|
||||
@classmethod
|
||||
def convert(cls):
|
||||
url = pecan.request.host_url
|
||||
|
||||
description = KubeUpgradeDescription()
|
||||
description.id = "kube-upgrade"
|
||||
description.links = [
|
||||
Link.make_link('self',
|
||||
url,
|
||||
'orchestration/kube-upgrade'),
|
||||
Link.make_link('strategy',
|
||||
url,
|
||||
'orchestration/kube-upgrade/strategy')]
|
||||
return description
|
||||
|
||||
|
||||
class KubeUpgradeAPI(rest.RestController):
|
||||
"""
|
||||
KubeUpgradeRest API
|
||||
"""
|
||||
@pecan.expose()
|
||||
def _lookup(self, key, *remainder):
|
||||
if 'strategy' == key:
|
||||
return KubeUpgradeStrategyAPI(), remainder
|
||||
else:
|
||||
pecan.abort(httplib.NOT_FOUND)
|
||||
|
||||
@wsme_pecan.wsexpose(KubeUpgradeDescription)
|
||||
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 KubeUpgradeDescription.convert()
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (c) 2015-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -19,6 +19,7 @@ class SwUpdateNames(Constants):
|
|||
SW_PATCH = Constant('sw-patch')
|
||||
SW_UPGRADE = Constant('sw-upgrade')
|
||||
FW_UPDATE = Constant('fw-update')
|
||||
KUBE_UPGRADE = Constant('kube-upgrade')
|
||||
|
||||
|
||||
@six.add_metaclass(Singleton)
|
||||
|
@ -72,7 +73,8 @@ SW_UPDATE_ALARM_RESTRICTION_TYPES = SwUpdateAlarmRestrictionTypes()
|
|||
SwUpdateNames = wsme_types.Enum(str,
|
||||
SW_UPDATE_NAME.SW_PATCH,
|
||||
SW_UPDATE_NAME.SW_UPGRADE,
|
||||
SW_UPDATE_NAME.FW_UPDATE)
|
||||
SW_UPDATE_NAME.FW_UPDATE,
|
||||
SW_UPDATE_NAME.KUBE_UPGRADE)
|
||||
SwUpdateApplyTypes = wsme_types.Enum(str,
|
||||
SW_UPDATE_APPLY_TYPE.SERIAL,
|
||||
SW_UPDATE_APPLY_TYPE.PARALLEL,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -33,6 +33,7 @@ MIN_PARALLEL_HOSTS = 2
|
|||
MAX_PARALLEL_PATCH_HOSTS = 100
|
||||
MAX_PARALLEL_UPGRADE_HOSTS = 10
|
||||
MAX_PARALLEL_FW_UPDATE_HOSTS = 5
|
||||
MAX_PARALLEL_KUBE_UPGRADE_HOSTS = 10
|
||||
|
||||
|
||||
def _get_sw_update_type_from_path(path):
|
||||
|
@ -43,6 +44,8 @@ def _get_sw_update_type_from_path(path):
|
|||
return SW_UPDATE_NAME.SW_UPGRADE
|
||||
elif 'fw-update' in split_path:
|
||||
return SW_UPDATE_NAME.FW_UPDATE
|
||||
elif 'kube-upgrade' in split_path:
|
||||
return SW_UPDATE_NAME.KUBE_UPGRADE
|
||||
else:
|
||||
DLOG.error("Unknown sw_update_type in path: %s" % path)
|
||||
return 'unknown'
|
||||
|
@ -201,6 +204,30 @@ class FwUpdateStrategyCreateData(wsme_types.Base):
|
|||
name='alarm-restrictions')
|
||||
|
||||
|
||||
class KubeUpgradeStrategyCreateData(wsme_types.Base):
|
||||
"""
|
||||
Kubernetes Upgrade Strategy - Create Data
|
||||
"""
|
||||
to_version = wsme_types.wsattr(six.text_type,
|
||||
mandatory=True,
|
||||
name='to-version')
|
||||
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')
|
||||
alarm_restrictions = wsme_types.wsattr(
|
||||
SwUpdateAlarmRestrictionTypes,
|
||||
mandatory=False,
|
||||
default=SW_UPDATE_ALARM_RESTRICTION_TYPES.STRICT,
|
||||
name='alarm-restrictions')
|
||||
|
||||
|
||||
class SwUpdateStrategyActionData(wsme_types.Base):
|
||||
"""
|
||||
Software Update Strategy - Action Data
|
||||
|
@ -633,3 +660,62 @@ class FwUpdateStrategyAPI(SwUpdateStrategyAPI):
|
|||
|
||||
DLOG.error("Unexpected result received, result=%s." % response.result)
|
||||
return pecan.abort(httplib.INTERNAL_SERVER_ERROR)
|
||||
|
||||
|
||||
class KubeUpgradeStrategyAPI(SwUpdateStrategyAPI):
|
||||
"""
|
||||
Kubernetes Upgrade Strategy Rest API
|
||||
"""
|
||||
@wsme_pecan.wsexpose(SwUpdateStrategyQueryData,
|
||||
body=KubeUpgradeStrategyCreateData,
|
||||
status_code=httplib.OK)
|
||||
def post(self, request_data):
|
||||
rpc_request = rpc.APIRequestCreateKubeUpgradeStrategy()
|
||||
rpc_request.sw_update_type = _get_sw_update_type_from_path(
|
||||
pecan.request.path)
|
||||
rpc_request.to_version = request_data.to_version
|
||||
rpc_request.controller_apply_type = SW_UPDATE_APPLY_TYPE.SERIAL
|
||||
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:
|
||||
return pecan.abort(
|
||||
httplib.BAD_REQUEST,
|
||||
"Invalid value for max-parallel-worker-hosts:(%s) < (%s)"
|
||||
% (request_data.max_parallel_worker_hosts,
|
||||
MIN_PARALLEL_HOSTS))
|
||||
if (request_data.max_parallel_worker_hosts >
|
||||
MAX_PARALLEL_KUBE_UPGRADE_HOSTS):
|
||||
return pecan.abort(
|
||||
httplib.BAD_REQUEST,
|
||||
"Invalid value for max-parallel-worker-hosts:(%s) > (%s)"
|
||||
% (request_data.max_parallel_worker_hosts,
|
||||
MAX_PARALLEL_KUBE_UPGRADE_HOSTS))
|
||||
rpc_request.max_parallel_worker_hosts = \
|
||||
request_data.max_parallel_worker_hosts
|
||||
rpc_request.default_instance_action = SW_UPDATE_INSTANCE_ACTION.MIGRATE
|
||||
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)
|
||||
|
||||
DLOG.error("Unexpected result received, result=%s." % response.result)
|
||||
return pecan.abort(httplib.INTERNAL_SERVER_ERROR)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2016,2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2016-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -69,4 +69,8 @@ def database_sw_update_get_list():
|
|||
elif objects.SW_UPDATE_TYPE.FW_UPDATE == sw_update.sw_update_type:
|
||||
fw_update_obj = objects.FwUpdate(sw_update.uuid, strategy_data)
|
||||
sw_update_objs.append(fw_update_obj)
|
||||
elif objects.SW_UPDATE_TYPE.KUBE_UPGRADE == sw_update.sw_update_type:
|
||||
kube_upgrade_obj = objects.KubeUpgrade(sw_update.uuid,
|
||||
strategy_data)
|
||||
sw_update_objs.append(kube_upgrade_obj)
|
||||
return sw_update_objs
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -27,6 +27,7 @@ class OperationTypes(Constants):
|
|||
SWACT_HOSTS = Constant('swact-hosts')
|
||||
FW_UPDATE_HOSTS = Constant('fw-update-hosts')
|
||||
FW_UPDATE_ABORT_HOSTS = Constant('fw-update-abort-hosts')
|
||||
KUBE_UPGRADE_HOSTS = Constant('kube-upgrade-hosts')
|
||||
START_INSTANCES = Constant('start-instances')
|
||||
START_INSTANCES_SERIAL = Constant('start-instances-serial')
|
||||
STOP_INSTANCES = Constant('stop-instances')
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -803,6 +803,161 @@ class HostDirector(object):
|
|||
|
||||
return host_operation
|
||||
|
||||
@coroutine
|
||||
def _nfvi_kube_host_upgrade_control_plane_callback(self):
|
||||
"""
|
||||
NFVI Kube Host Upgrade Control Plane Callback
|
||||
"""
|
||||
from nfv_vim import directors
|
||||
|
||||
response = (yield)
|
||||
DLOG.verbose("NFVI Kube Host Upgrade Control Plane response=%s."
|
||||
% response)
|
||||
if not response['completed']:
|
||||
DLOG.info("Kube Host Upgrade Control Plane failed. Host:%s, reason=%s."
|
||||
% (response['host_name'], response['reason']))
|
||||
|
||||
host_table = tables.tables_get_host_table()
|
||||
host = host_table.get(response['host_name'], None)
|
||||
if host is None:
|
||||
DLOG.verbose("Host %s does not exist." % response['host_name'])
|
||||
return
|
||||
|
||||
if self._host_operation is None:
|
||||
DLOG.verbose("No host %s operation inprogress." % host.name)
|
||||
return
|
||||
|
||||
if OPERATION_TYPE.KUBE_UPGRADE_HOSTS != self._host_operation.operation_type:
|
||||
DLOG.verbose("Unexpected host %s operation %s, ignoring."
|
||||
% (host.name, self._host_operation.operation_type))
|
||||
return
|
||||
|
||||
sw_mgmt_director = directors.get_sw_mgmt_director()
|
||||
sw_mgmt_director.kube_host_upgrade_control_plane_failed(host)
|
||||
|
||||
def _nfvi_kube_host_upgrade_control_plane(self,
|
||||
host_uuid,
|
||||
host_name,
|
||||
force):
|
||||
"""
|
||||
NFVI Kube Host Upgrade Control Plane
|
||||
"""
|
||||
nfvi.nfvi_kube_host_upgrade_control_plane(
|
||||
host_uuid,
|
||||
host_name,
|
||||
force,
|
||||
self._nfvi_kube_host_upgrade_control_plane_callback())
|
||||
|
||||
def kube_upgrade_hosts_control_plane(self, host_names, force):
|
||||
"""
|
||||
Kube Upgrade Hosts Control Plane for multiple hosts
|
||||
"""
|
||||
DLOG.info("Kube Host Upgrade control plane for hosts: %s" % host_names)
|
||||
|
||||
host_operation = \
|
||||
Operation(OPERATION_TYPE.KUBE_UPGRADE_HOSTS)
|
||||
|
||||
if self._host_operation is not None:
|
||||
DLOG.debug("Canceling previous host operation %s, before "
|
||||
"continuing with host operation %s."
|
||||
% (self._host_operation.operation_type,
|
||||
host_operation.operation_type))
|
||||
self._host_operation = None
|
||||
|
||||
host_table = tables.tables_get_host_table()
|
||||
for host_name in host_names:
|
||||
host = host_table.get(host_name, None)
|
||||
if host is None:
|
||||
reason = "Unknown host %s given." % host_name
|
||||
DLOG.info(reason)
|
||||
host_operation.set_failed(reason)
|
||||
return host_operation
|
||||
|
||||
host_operation.add_host(host.name, OPERATION_STATE.INPROGRESS)
|
||||
self._nfvi_kube_host_upgrade_control_plane(host.uuid,
|
||||
host.name,
|
||||
force)
|
||||
|
||||
if host_operation.is_inprogress():
|
||||
self._host_operation = host_operation
|
||||
|
||||
return host_operation
|
||||
|
||||
@coroutine
|
||||
def _nfvi_kube_host_upgrade_kubelet_callback(self):
|
||||
"""
|
||||
NFVI Kube Host Upgrade Kubelet Callback (for a single host)
|
||||
"""
|
||||
from nfv_vim import directors
|
||||
|
||||
response = (yield)
|
||||
DLOG.verbose("NFVI Kube Host Upgrade Kubelet response=%s."
|
||||
% response)
|
||||
if not response['completed']:
|
||||
DLOG.info("Kube Host Upgrade Kubelet failed. Host:%s, reason=%s."
|
||||
% (response['host_name'], response['reason']))
|
||||
|
||||
host_table = tables.tables_get_host_table()
|
||||
host = host_table.get(response['host_name'], None)
|
||||
if host is None:
|
||||
DLOG.verbose("Host %s does not exist." % response['host_name'])
|
||||
return
|
||||
|
||||
if self._host_operation is None:
|
||||
DLOG.verbose("No host %s operation inprogress." % host.name)
|
||||
return
|
||||
|
||||
if OPERATION_TYPE.KUBE_UPGRADE_HOSTS != self._host_operation.operation_type:
|
||||
DLOG.verbose("Unexpected host %s operation %s, ignoring."
|
||||
% (host.name, self._host_operation.operation_type))
|
||||
return
|
||||
|
||||
sw_mgmt_director = directors.get_sw_mgmt_director()
|
||||
sw_mgmt_director.kube_host_upgrade_kubelet_failed(host)
|
||||
|
||||
def _nfvi_kube_host_upgrade_kubelet(self, host_uuid, host_name, force):
|
||||
"""
|
||||
NFVI Kube Host Upgrade Kubelet
|
||||
"""
|
||||
nfvi.nfvi_kube_host_upgrade_kubelet(
|
||||
host_uuid,
|
||||
host_name,
|
||||
force,
|
||||
self._nfvi_kube_host_upgrade_kubelet_callback())
|
||||
|
||||
def kube_upgrade_hosts_kubelet(self, host_names, force):
|
||||
"""
|
||||
Kube Upgrade Hosts Kubelet for multiple hosts
|
||||
"""
|
||||
DLOG.info("Kube Host Upgrade kubelet for hosts: %s" % host_names)
|
||||
|
||||
host_operation = \
|
||||
Operation(OPERATION_TYPE.KUBE_UPGRADE_HOSTS)
|
||||
|
||||
if self._host_operation is not None:
|
||||
DLOG.debug("Canceling previous host operation %s, before "
|
||||
"continuing with host operation %s."
|
||||
% (self._host_operation.operation_type,
|
||||
host_operation.operation_type))
|
||||
self._host_operation = None
|
||||
|
||||
host_table = tables.tables_get_host_table()
|
||||
for host_name in host_names:
|
||||
host = host_table.get(host_name, None)
|
||||
if host is None:
|
||||
reason = "Unknown host %s given." % host_name
|
||||
DLOG.info(reason)
|
||||
host_operation.set_failed(reason)
|
||||
return host_operation
|
||||
|
||||
host_operation.add_host(host.name, OPERATION_STATE.INPROGRESS)
|
||||
self._nfvi_kube_host_upgrade_kubelet(host.uuid, host.name, force)
|
||||
|
||||
if host_operation.is_inprogress():
|
||||
self._host_operation = host_operation
|
||||
|
||||
return host_operation
|
||||
|
||||
def disable_host_services(self, host_names, service):
|
||||
"""
|
||||
Disable a host service on a list of hosts
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -134,6 +134,42 @@ class SwMgmtDirector(object):
|
|||
self._sw_update.strategy)
|
||||
return strategy_uuid, ''
|
||||
|
||||
def create_kube_upgrade_strategy(self,
|
||||
storage_apply_type,
|
||||
worker_apply_type,
|
||||
max_parallel_worker_hosts,
|
||||
alarm_restrictions,
|
||||
to_version,
|
||||
callback):
|
||||
"""
|
||||
Create Kubernetes Upgrade 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"
|
||||
return None, reason
|
||||
|
||||
self._sw_update = objects.KubeUpgrade()
|
||||
success, reason = self._sw_update.strategy_build(
|
||||
strategy_uuid,
|
||||
storage_apply_type,
|
||||
worker_apply_type,
|
||||
max_parallel_worker_hosts,
|
||||
alarm_restrictions,
|
||||
self._ignore_alarms,
|
||||
to_version,
|
||||
self._single_controller)
|
||||
|
||||
schedule.schedule_function_call(callback,
|
||||
success,
|
||||
reason,
|
||||
self._sw_update.strategy)
|
||||
return strategy_uuid, ''
|
||||
|
||||
def apply_sw_update_strategy(self, strategy_uuid, stage_id, callback):
|
||||
"""
|
||||
Apply Software Update Strategy
|
||||
|
@ -245,6 +281,24 @@ class SwMgmtDirector(object):
|
|||
self._sw_update.handle_event(
|
||||
strategy.STRATEGY_EVENT.HOST_FW_UPDATE_FAILED, host)
|
||||
|
||||
def kube_host_upgrade_control_plane_failed(self, host):
|
||||
"""
|
||||
Called when a kube host upgrade for control plane fails
|
||||
"""
|
||||
if self._sw_update is not None:
|
||||
self._sw_update.handle_event(
|
||||
strategy.STRATEGY_EVENT.KUBE_HOST_UPGRADE_CONTROL_PLANE_FAILED,
|
||||
host)
|
||||
|
||||
def kube_host_upgrade_kubelet_failed(self, host):
|
||||
"""
|
||||
Called when a kube host upgrade for kubelet fails
|
||||
"""
|
||||
if self._sw_update is not None:
|
||||
self._sw_update.handle_event(
|
||||
strategy.STRATEGY_EVENT.KUBE_HOST_UPGRADE_KUBELET_FAILED,
|
||||
host)
|
||||
|
||||
def host_audit(self, host):
|
||||
"""
|
||||
Called when a host audit is to be performed
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2016 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -342,6 +342,172 @@ _event_templates = {
|
|||
}
|
||||
}
|
||||
},
|
||||
event_log.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_START: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'event_type': event_log.EVENT_TYPE.ACTION_EVENT,
|
||||
'importance': event_log.EVENT_IMPORTANCE.HIGH,
|
||||
'reason_text': "Kubernetes upgrade auto-apply start",
|
||||
'exclude_event_context': [],
|
||||
'event_context_data': {
|
||||
event_log.EVENT_CONTEXT.ADMIN: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'reason_text': "Kubernetes upgrade auto-apply start",
|
||||
}
|
||||
}
|
||||
},
|
||||
event_log.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_INPROGRESS: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'event_type': event_log.EVENT_TYPE.ACTION_EVENT,
|
||||
'importance': event_log.EVENT_IMPORTANCE.HIGH,
|
||||
'reason_text': "Kubernetes upgrade auto-apply inprogress",
|
||||
'exclude_event_context': [],
|
||||
'event_context_data': {
|
||||
event_log.EVENT_CONTEXT.ADMIN: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'reason_text': "Kubernetes upgrade auto-apply inprogress",
|
||||
}
|
||||
}
|
||||
},
|
||||
event_log.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_REJECTED: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'event_type': event_log.EVENT_TYPE.ACTION_EVENT,
|
||||
'importance': event_log.EVENT_IMPORTANCE.HIGH,
|
||||
'reason_text': "Kubernetes upgrade auto-apply rejected",
|
||||
'exclude_event_context': [],
|
||||
'event_context_data': {
|
||||
event_log.EVENT_CONTEXT.ADMIN: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'reason_text': "Kubernetes upgrade auto-apply rejected%(reason)s",
|
||||
}
|
||||
}
|
||||
},
|
||||
event_log.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_CANCELLED: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'event_type': event_log.EVENT_TYPE.ACTION_EVENT,
|
||||
'importance': event_log.EVENT_IMPORTANCE.HIGH,
|
||||
'reason_text': "Kubernetes upgrade auto-apply cancelled",
|
||||
'exclude_event_context': [],
|
||||
'event_context_data': {
|
||||
event_log.EVENT_CONTEXT.ADMIN: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'reason_text': "Kubernetes upgrade auto-apply cancelled%(reason)s",
|
||||
}
|
||||
}
|
||||
},
|
||||
event_log.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_FAILED: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'event_type': event_log.EVENT_TYPE.ACTION_EVENT,
|
||||
'importance': event_log.EVENT_IMPORTANCE.HIGH,
|
||||
'reason_text': "Kubernetes upgrade auto-apply failed",
|
||||
'exclude_event_context': [],
|
||||
'event_context_data': {
|
||||
event_log.EVENT_CONTEXT.ADMIN: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'reason_text': "Kubernetes upgrade auto-apply failed%(reason)s",
|
||||
}
|
||||
}
|
||||
},
|
||||
event_log.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_COMPLETED: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'event_type': event_log.EVENT_TYPE.ACTION_EVENT,
|
||||
'importance': event_log.EVENT_IMPORTANCE.HIGH,
|
||||
'reason_text': "Kubernetes upgrade auto-apply completed",
|
||||
'exclude_event_context': [],
|
||||
'event_context_data': {
|
||||
event_log.EVENT_CONTEXT.ADMIN: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'reason_text': "Kubernetes upgrade auto-apply completed",
|
||||
}
|
||||
}
|
||||
},
|
||||
event_log.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_ABORT: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'event_type': event_log.EVENT_TYPE.ACTION_EVENT,
|
||||
'importance': event_log.EVENT_IMPORTANCE.HIGH,
|
||||
'reason_text': "Kubernetes upgrade auto-apply abort",
|
||||
'exclude_event_context': [],
|
||||
'event_context_data': {
|
||||
event_log.EVENT_CONTEXT.ADMIN: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'reason_text': "Kubernetes upgrade auto-apply abort",
|
||||
}
|
||||
}
|
||||
},
|
||||
event_log.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_ABORTING: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'event_type': event_log.EVENT_TYPE.ACTION_EVENT,
|
||||
'importance': event_log.EVENT_IMPORTANCE.HIGH,
|
||||
'reason_text': "Kubernetes upgrade auto-apply aborting",
|
||||
'exclude_event_context': [],
|
||||
'event_context_data': {
|
||||
event_log.EVENT_CONTEXT.ADMIN: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'reason_text': "Kubernetes upgrade auto-apply aborting",
|
||||
}
|
||||
}
|
||||
},
|
||||
event_log.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_ABORT_REJECTED: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'event_type': event_log.EVENT_TYPE.ACTION_EVENT,
|
||||
'importance': event_log.EVENT_IMPORTANCE.HIGH,
|
||||
'reason_text': "Kubernetes upgrade auto-apply abort rejected",
|
||||
'exclude_event_context': [],
|
||||
'event_context_data': {
|
||||
event_log.EVENT_CONTEXT.ADMIN: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'reason_text': "Kubernetes upgrade auto-apply abort "
|
||||
"rejected%(reason)s",
|
||||
}
|
||||
}
|
||||
},
|
||||
event_log.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_ABORT_FAILED: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'event_type': event_log.EVENT_TYPE.ACTION_EVENT,
|
||||
'importance': event_log.EVENT_IMPORTANCE.HIGH,
|
||||
'reason_text': "Kubernetes upgrade auto-apply abort failed",
|
||||
'exclude_event_context': [],
|
||||
'event_context_data': {
|
||||
event_log.EVENT_CONTEXT.ADMIN: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'reason_text': "Kubernetes upgrade auto-apply abort failed%(reason)s",
|
||||
}
|
||||
}
|
||||
},
|
||||
event_log.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_ABORTED: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'event_type': event_log.EVENT_TYPE.ACTION_EVENT,
|
||||
'importance': event_log.EVENT_IMPORTANCE.HIGH,
|
||||
'reason_text': "Kubernetes upgrade auto-apply aborted",
|
||||
'exclude_event_context': [],
|
||||
'event_context_data': {
|
||||
event_log.EVENT_CONTEXT.ADMIN: {
|
||||
'entity_type': "orchestration",
|
||||
'entity': "orchestration=kube-upgrade",
|
||||
'reason_text': "Kubernetes upgrade auto-apply aborted",
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2016 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -187,6 +187,9 @@ def _vim_api_message_handler(connection, msg):
|
|||
elif rpc.RPC_MSG_TYPE.CREATE_SW_UPDATE_STRATEGY_REQUEST == msg.type:
|
||||
vim_sw_update_api_create_strategy(connection, msg)
|
||||
|
||||
elif rpc.RPC_MSG_TYPE.CREATE_KUBE_UPGRADE_STRATEGY_REQUEST == msg.type:
|
||||
vim_sw_update_api_create_strategy(connection, msg)
|
||||
|
||||
elif rpc.RPC_MSG_TYPE.CREATE_SW_UPGRADE_STRATEGY_REQUEST == msg.type:
|
||||
vim_sw_update_api_create_strategy(connection, msg)
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -124,6 +124,8 @@ def _nfvi_sw_update_get_callback():
|
|||
sw_update_type = 'sw-upgrade'
|
||||
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_UPGRADE:
|
||||
sw_update_type = 'kube-upgrade'
|
||||
|
||||
if sw_update.strategy.is_applying() or sw_update.strategy.is_aborting():
|
||||
in_progress = True
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -113,6 +113,15 @@ def vim_sw_update_api_create_strategy(connection, msg):
|
|||
default_instance_action,
|
||||
alarm_restrictions,
|
||||
_vim_sw_update_api_create_strategy_callback)
|
||||
elif 'kube-upgrade' == msg.sw_update_type:
|
||||
to_version = msg.to_version
|
||||
uuid, reason = sw_mgmt_director.create_kube_upgrade_strategy(
|
||||
storage_apply_type,
|
||||
worker_apply_type,
|
||||
max_parallel_worker_hosts,
|
||||
alarm_restrictions,
|
||||
to_version,
|
||||
_vim_sw_update_api_create_strategy_callback)
|
||||
else:
|
||||
DLOG.error("Invalid message name: %s" % msg.sw_update_type)
|
||||
response = rpc.APIResponseCreateSwUpdateStrategy()
|
||||
|
@ -164,13 +173,15 @@ def vim_sw_update_api_apply_strategy(connection, msg):
|
|||
"""
|
||||
Handle Sw-Update Apply Strategy API request
|
||||
"""
|
||||
DLOG.info("Apply sw-update strategy.")
|
||||
DLOG.info("Apply sw-update strategy: (%s) called." % msg.sw_update_type)
|
||||
if 'sw-patch' == msg.sw_update_type:
|
||||
sw_update_type = objects.SW_UPDATE_TYPE.SW_PATCH
|
||||
elif 'sw-upgrade' == msg.sw_update_type:
|
||||
sw_update_type = objects.SW_UPDATE_TYPE.SW_UPGRADE
|
||||
elif 'fw-update' == msg.sw_update_type:
|
||||
sw_update_type = objects.SW_UPDATE_TYPE.FW_UPDATE
|
||||
elif 'kube-upgrade' == msg.sw_update_type:
|
||||
sw_update_type = objects.SW_UPDATE_TYPE.KUBE_UPGRADE
|
||||
else:
|
||||
DLOG.error("Invalid message name: %s" % msg.sw_update_type)
|
||||
sw_update_type = 'unknown'
|
||||
|
@ -226,6 +237,8 @@ def vim_sw_update_api_abort_strategy(connection, msg):
|
|||
sw_update_type = objects.SW_UPDATE_TYPE.SW_UPGRADE
|
||||
elif 'fw-update' == msg.sw_update_type:
|
||||
sw_update_type = objects.SW_UPDATE_TYPE.FW_UPDATE
|
||||
elif 'kube-upgrade' == msg.sw_update_type:
|
||||
sw_update_type = objects.SW_UPDATE_TYPE.KUBE_UPGRADE
|
||||
else:
|
||||
DLOG.error("Invalid message name: %s" % msg.sw_update_type)
|
||||
sw_update_type = 'unknown'
|
||||
|
@ -278,6 +291,8 @@ def vim_sw_update_api_delete_strategy(connection, msg):
|
|||
sw_update_type = objects.SW_UPDATE_TYPE.SW_UPGRADE
|
||||
elif 'fw-update' == msg.sw_update_type:
|
||||
sw_update_type = objects.SW_UPDATE_TYPE.FW_UPDATE
|
||||
elif 'kube-upgrade' == msg.sw_update_type:
|
||||
sw_update_type = objects.SW_UPDATE_TYPE.KUBE_UPGRADE
|
||||
else:
|
||||
DLOG.error("Invalid message name: %s" % msg.sw_update_type)
|
||||
sw_update_type = 'unknown'
|
||||
|
@ -309,6 +324,8 @@ def vim_sw_update_api_get_strategy(connection, msg):
|
|||
sw_update_type = objects.SW_UPDATE_TYPE.SW_UPGRADE
|
||||
elif 'fw-update' == msg.sw_update_type:
|
||||
sw_update_type = objects.SW_UPDATE_TYPE.FW_UPDATE
|
||||
elif 'kube-upgrade' == msg.sw_update_type:
|
||||
sw_update_type = objects.SW_UPDATE_TYPE.KUBE_UPGRADE
|
||||
else:
|
||||
DLOG.error("Invalid message name: %s" % msg.sw_update_type)
|
||||
sw_update_type = 'unknown'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -100,6 +100,9 @@ from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_get_host # noqa: F401
|
|||
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_get_host_device # noqa: F401
|
||||
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_get_host_devices # noqa: F401
|
||||
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_get_hosts # noqa: F401
|
||||
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_get_kube_host_upgrade_list # noqa: F401
|
||||
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_info # noqa: F401
|
||||
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_get_system_state # noqa: F401
|
||||
|
@ -107,6 +110,13 @@ from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_get_terminating_pods
|
|||
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_get_upgrade # noqa: F401
|
||||
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_host_device_image_update # noqa: F401
|
||||
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_host_device_image_update_abort # noqa: F401
|
||||
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_kube_host_upgrade_control_plane # noqa: F401
|
||||
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_kube_host_upgrade_kubelet # noqa: F401
|
||||
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_kube_upgrade_cleanup # noqa: F401
|
||||
from nfv_vim.nfvi._nfvi_infrastructure_module import nfvi_kube_upgrade_complete # noqa: F401
|
||||
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_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
|
||||
|
@ -160,6 +170,7 @@ from nfv_vim.nfvi._nfvi_network_module import nfvi_remove_router_from_agent # n
|
|||
from nfv_vim.nfvi._nfvi_network_module import nfvi_update_network # noqa: F401
|
||||
from nfv_vim.nfvi._nfvi_network_module import nfvi_update_subnet # noqa: F401
|
||||
|
||||
from nfv_vim.nfvi._nfvi_sw_mgmt_module import nfvi_sw_mgmt_apply_updates # noqa: F401
|
||||
from nfv_vim.nfvi._nfvi_sw_mgmt_module import nfvi_sw_mgmt_query_hosts # noqa: F401
|
||||
from nfv_vim.nfvi._nfvi_sw_mgmt_module import nfvi_sw_mgmt_query_updates # noqa: F401
|
||||
from nfv_vim.nfvi._nfvi_sw_mgmt_module import nfvi_sw_mgmt_update_host # noqa: F401
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -100,6 +100,111 @@ def nfvi_host_device_image_update_abort(host_uuid, host_name, callback):
|
|||
return cmd_id
|
||||
|
||||
|
||||
def nfvi_kube_host_upgrade_control_plane(host_uuid, host_name, force, callback):
|
||||
"""
|
||||
Kube Host Upgrade Control Plane
|
||||
"""
|
||||
cmd_id = _infrastructure_plugin.invoke_plugin(
|
||||
'kube_host_upgrade_control_plane',
|
||||
host_uuid,
|
||||
host_name,
|
||||
force,
|
||||
callback=callback)
|
||||
return cmd_id
|
||||
|
||||
|
||||
def nfvi_kube_host_upgrade_kubelet(host_uuid, host_name, force, callback):
|
||||
"""
|
||||
Kube Host Upgrade Kubelet
|
||||
"""
|
||||
cmd_id = _infrastructure_plugin.invoke_plugin(
|
||||
'kube_host_upgrade_kubelet',
|
||||
host_uuid,
|
||||
host_name,
|
||||
force,
|
||||
callback=callback)
|
||||
return cmd_id
|
||||
|
||||
|
||||
def nfvi_kube_upgrade_cleanup(callback):
|
||||
"""
|
||||
Kube Upgrade Cleanup
|
||||
"""
|
||||
cmd_id = _infrastructure_plugin.invoke_plugin(
|
||||
'kube_upgrade_cleanup',
|
||||
callback=callback)
|
||||
return cmd_id
|
||||
|
||||
|
||||
def nfvi_kube_upgrade_complete(callback):
|
||||
"""
|
||||
Kube Upgrade Complete
|
||||
"""
|
||||
cmd_id = _infrastructure_plugin.invoke_plugin(
|
||||
'kube_upgrade_complete',
|
||||
callback=callback)
|
||||
return cmd_id
|
||||
|
||||
|
||||
def nfvi_kube_upgrade_download_images(callback):
|
||||
"""
|
||||
Kube Upgrade Download Images
|
||||
"""
|
||||
cmd_id = _infrastructure_plugin.invoke_plugin(
|
||||
'kube_upgrade_download_images',
|
||||
callback=callback)
|
||||
return cmd_id
|
||||
|
||||
|
||||
def nfvi_kube_upgrade_networking(callback):
|
||||
"""
|
||||
Kube Upgrade Networking
|
||||
"""
|
||||
cmd_id = _infrastructure_plugin.invoke_plugin('kube_upgrade_networking',
|
||||
callback=callback)
|
||||
return cmd_id
|
||||
|
||||
|
||||
def nfvi_kube_upgrade_start(to_version, force, alarm_ignore_list, callback):
|
||||
"""
|
||||
Kube Upgrade Start
|
||||
"""
|
||||
cmd_id = _infrastructure_plugin.invoke_plugin(
|
||||
'kube_upgrade_start',
|
||||
to_version=to_version,
|
||||
force=force,
|
||||
alarm_ignore_list=alarm_ignore_list,
|
||||
callback=callback)
|
||||
return cmd_id
|
||||
|
||||
|
||||
def nfvi_get_kube_host_upgrade_list(callback):
|
||||
"""
|
||||
Get kube host upgrade list
|
||||
"""
|
||||
cmd_id = _infrastructure_plugin.invoke_plugin('get_kube_host_upgrade_list',
|
||||
callback=callback)
|
||||
return cmd_id
|
||||
|
||||
|
||||
def nfvi_get_kube_upgrade(callback):
|
||||
"""
|
||||
Get kube upgrade
|
||||
"""
|
||||
cmd_id = _infrastructure_plugin.invoke_plugin('get_kube_upgrade',
|
||||
callback=callback)
|
||||
return cmd_id
|
||||
|
||||
|
||||
def nfvi_get_kube_version_list(callback):
|
||||
"""
|
||||
Get kube version list
|
||||
"""
|
||||
cmd_id = _infrastructure_plugin.invoke_plugin('get_kube_version_list',
|
||||
callback=callback)
|
||||
return cmd_id
|
||||
|
||||
|
||||
def nfvi_get_upgrade(callback):
|
||||
"""
|
||||
Get upgrade
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2016 Wind River Systems, Inc.
|
||||
# Copyright (c) 2016-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -37,6 +37,16 @@ def nfvi_sw_mgmt_update_host(host_name, callback):
|
|||
return cmd_id
|
||||
|
||||
|
||||
def nfvi_sw_mgmt_apply_updates(patch_names, callback):
|
||||
"""
|
||||
Apply Software Patches
|
||||
"""
|
||||
cmd_id = _sw_mgmt_plugin.invoke_plugin('apply_patches',
|
||||
patch_names,
|
||||
callback=callback)
|
||||
return cmd_id
|
||||
|
||||
|
||||
def nfvi_sw_mgmt_update_hosts(host_names, callback):
|
||||
"""
|
||||
Apply Software Patch to a list of hosts
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -48,6 +48,10 @@ from nfv_vim.nfvi.objects.v1._instance_group import InstanceGroup # noqa: F401
|
|||
from nfv_vim.nfvi.objects.v1._instance_type import INSTANCE_TYPE_EXTENSION # noqa: F401
|
||||
from nfv_vim.nfvi.objects.v1._instance_type import InstanceType # noqa: F401
|
||||
from nfv_vim.nfvi.objects.v1._instance_type import InstanceTypeAttributes # noqa: F401
|
||||
from nfv_vim.nfvi.objects.v1._kube_upgrade import KUBE_UPGRADE_STATE # noqa: F401
|
||||
from nfv_vim.nfvi.objects.v1._kube_upgrade import KubeHostUpgrade # noqa: F401
|
||||
from nfv_vim.nfvi.objects.v1._kube_upgrade import KubeUpgrade # noqa: F401
|
||||
from nfv_vim.nfvi.objects.v1._kube_upgrade import KubeVersion # noqa: F401
|
||||
from nfv_vim.nfvi.objects.v1._network import Network # noqa: F401
|
||||
from nfv_vim.nfvi.objects.v1._network import NETWORK_ADMIN_STATE # noqa: F401
|
||||
from nfv_vim.nfvi.objects.v1._network import NETWORK_AVAIL_STATUS # noqa: F401
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
#
|
||||
# Copyright (c) 2016-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
import six
|
||||
|
||||
from nfv_common.helpers import Constant
|
||||
from nfv_common.helpers import Constants
|
||||
from nfv_common.helpers import Singleton
|
||||
|
||||
from nfv_vim.nfvi.objects.v1._object import ObjectData
|
||||
|
||||
|
||||
@six.add_metaclass(Singleton)
|
||||
class KubeUpgradeState(Constants):
|
||||
"""
|
||||
Kube Upgrade State Constants
|
||||
These values are copied from sysinv/common/kubernetes.py
|
||||
"""
|
||||
|
||||
KUBE_UPGRADE_STARTED = Constant('upgrade-started')
|
||||
KUBE_UPGRADE_DOWNLOADING_IMAGES = Constant('downloading-images')
|
||||
KUBE_UPGRADE_DOWNLOADING_IMAGES_FAILED = Constant('downloading-images-failed')
|
||||
KUBE_UPGRADE_DOWNLOADED_IMAGES = Constant('downloaded-images')
|
||||
KUBE_UPGRADING_FIRST_MASTER = Constant('upgrading-first-master')
|
||||
KUBE_UPGRADING_FIRST_MASTER_FAILED = Constant('upgrading-first-master-failed')
|
||||
KUBE_UPGRADED_FIRST_MASTER = Constant('upgraded-first-master')
|
||||
KUBE_UPGRADING_NETWORKING = Constant('upgrading-networking')
|
||||
KUBE_UPGRADING_NETWORKING_FAILED = Constant('upgrading-networking-failed')
|
||||
KUBE_UPGRADED_NETWORKING = Constant('upgraded-networking')
|
||||
KUBE_UPGRADING_SECOND_MASTER = Constant('upgrading-second-master')
|
||||
KUBE_UPGRADING_SECOND_MASTER_FAILED = Constant('upgrading-second-master-failed')
|
||||
KUBE_UPGRADED_SECOND_MASTER = Constant('upgraded-second-master')
|
||||
KUBE_UPGRADING_KUBELETS = Constant('upgrading-kubelets')
|
||||
KUBE_UPGRADE_COMPLETE = Constant('upgrade-complete')
|
||||
|
||||
|
||||
# Kube Upgrade Constant Instantiation
|
||||
KUBE_UPGRADE_STATE = KubeUpgradeState()
|
||||
|
||||
|
||||
class KubeHostUpgrade(ObjectData):
|
||||
"""
|
||||
NFVI Kube Host Upgrade Object
|
||||
"""
|
||||
def __init__(self,
|
||||
host_id,
|
||||
host_uuid,
|
||||
target_version,
|
||||
control_plane_version,
|
||||
kubelet_version,
|
||||
status):
|
||||
super(KubeHostUpgrade, self).__init__('1.0.0')
|
||||
self.update(
|
||||
dict(host_id=host_id,
|
||||
host_uuid=host_uuid,
|
||||
target_version=target_version,
|
||||
control_plane_version=control_plane_version,
|
||||
kubelet_version=kubelet_version,
|
||||
status=status
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class KubeUpgrade(ObjectData):
|
||||
"""
|
||||
NFVI Kube Upgrade Object
|
||||
"""
|
||||
def __init__(self, state, from_version, to_version):
|
||||
super(KubeUpgrade, self).__init__('1.0.0')
|
||||
self.update(
|
||||
dict(state=state,
|
||||
from_version=from_version,
|
||||
to_version=to_version
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class KubeVersion(ObjectData):
|
||||
"""
|
||||
NFVI Kube Version Object
|
||||
"""
|
||||
def __init__(self,
|
||||
kube_version,
|
||||
state,
|
||||
target,
|
||||
upgrade_from,
|
||||
downgrade_to,
|
||||
applied_patches,
|
||||
available_patches):
|
||||
super(KubeVersion, self).__init__('1.0.0')
|
||||
self.update(
|
||||
dict(kube_version=kube_version,
|
||||
state=state,
|
||||
target=target,
|
||||
upgrade_from=upgrade_from,
|
||||
downgrade_to=downgrade_to,
|
||||
applied_patches=applied_patches,
|
||||
available_patches=available_patches
|
||||
)
|
||||
)
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -26,6 +26,7 @@ from nfv_vim.objects._instance_group import InstanceGroup # noqa: F401
|
|||
from nfv_vim.objects._instance_type import INSTANCE_TYPE_EXTENSION # noqa: F401
|
||||
from nfv_vim.objects._instance_type import InstanceType # noqa: F401
|
||||
from nfv_vim.objects._instance_type import InstanceTypeAttributes # noqa: F401
|
||||
from nfv_vim.objects._kube_upgrade import KubeUpgrade # noqa: F401
|
||||
from nfv_vim.objects._network import Network # noqa: F401
|
||||
from nfv_vim.objects._network import NetworkProviderData # noqa: F401
|
||||
from nfv_vim.objects._service_host import ServiceHost # noqa: F401
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
#
|
||||
# Copyright (c) 2020-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
from nfv_common import debug
|
||||
|
||||
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.kube_upgrade')
|
||||
|
||||
|
||||
class KubeUpgrade(SwUpdate):
|
||||
"""
|
||||
Kubernetes Upgrade Object
|
||||
"""
|
||||
def __init__(self, sw_update_uuid=None, strategy_data=None):
|
||||
super(KubeUpgrade, self).__init__(
|
||||
sw_update_type=SW_UPDATE_TYPE.KUBE_UPGRADE,
|
||||
sw_update_uuid=sw_update_uuid,
|
||||
strategy_data=strategy_data)
|
||||
|
||||
self._kube_upgrade_hosts = list()
|
||||
|
||||
def strategy_build(self,
|
||||
strategy_uuid,
|
||||
storage_apply_type,
|
||||
worker_apply_type,
|
||||
max_parallel_worker_hosts,
|
||||
alarm_restrictions,
|
||||
ignore_alarms,
|
||||
to_version,
|
||||
single_controller):
|
||||
"""
|
||||
Create a kubernetes upgrade strategy
|
||||
"""
|
||||
from nfv_vim import strategy
|
||||
|
||||
if self._strategy:
|
||||
reason = "strategy already exists"
|
||||
return False, reason
|
||||
|
||||
self._strategy = \
|
||||
strategy.KubeUpgradeStrategy(strategy_uuid,
|
||||
storage_apply_type,
|
||||
worker_apply_type,
|
||||
max_parallel_worker_hosts,
|
||||
alarm_restrictions,
|
||||
ignore_alarms,
|
||||
to_version,
|
||||
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 kubernetes upgrade strategy complete
|
||||
"""
|
||||
DLOG.info("Kubernetes upgrade 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.KUBE_UPGRADE_AUTO_APPLY_INPROGRESS,
|
||||
SW_UPDATE_ALARM_TYPES.APPLY_ABORTING:
|
||||
alarm.ALARM_TYPE.KUBE_UPGRADE_AUTO_APPLY_ABORTING,
|
||||
SW_UPDATE_ALARM_TYPES.APPLY_FAILED:
|
||||
alarm.ALARM_TYPE.KUBE_UPGRADE_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.KUBE_UPGRADE_AUTO_APPLY_START,
|
||||
SW_UPDATE_EVENT_IDS.APPLY_INPROGRESS:
|
||||
event_log.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_INPROGRESS,
|
||||
SW_UPDATE_EVENT_IDS.APPLY_REJECTED:
|
||||
event_log.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_REJECTED,
|
||||
SW_UPDATE_EVENT_IDS.APPLY_CANCELLED:
|
||||
event_log.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_CANCELLED,
|
||||
SW_UPDATE_EVENT_IDS.APPLY_FAILED:
|
||||
event_log.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_FAILED,
|
||||
SW_UPDATE_EVENT_IDS.APPLY_COMPLETED:
|
||||
event_log.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_COMPLETED,
|
||||
SW_UPDATE_EVENT_IDS.APPLY_ABORT:
|
||||
event_log.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_ABORT,
|
||||
SW_UPDATE_EVENT_IDS.APPLY_ABORTING:
|
||||
event_log.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_ABORTING,
|
||||
SW_UPDATE_EVENT_IDS.APPLY_ABORT_REJECTED:
|
||||
event_log.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_ABORT_REJECTED,
|
||||
SW_UPDATE_EVENT_IDS.APPLY_ABORT_FAILED:
|
||||
event_log.EVENT_ID.KUBE_UPGRADE_AUTO_APPLY_ABORT_FAILED,
|
||||
SW_UPDATE_EVENT_IDS.APPLY_ABORTED:
|
||||
event_log.EVENT_ID.KUBE_UPGRADE_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 kube_upgrade_host in self._kube_upgrade_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)
|
||||
|
||||
if not self.nfvi_update():
|
||||
DLOG.info("Audit no longer needed.")
|
||||
break
|
||||
|
||||
DLOG.verbose("Audit kube upgrade still running, timer_id=%s." %
|
||||
timer_id)
|
||||
|
||||
self._nfvi_timer_id = None
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2016-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2016-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -30,6 +30,7 @@ class SwUpdateTypes(Constants):
|
|||
SW_PATCH = Constant('sw-patch')
|
||||
SW_UPGRADE = Constant('sw-upgrade')
|
||||
FW_UPDATE = Constant('fw-update')
|
||||
KUBE_UPGRADE = Constant('kube-upgrade')
|
||||
|
||||
|
||||
@six.add_metaclass(Singleton)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2016 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -73,6 +73,7 @@ from nfv_vim.rpc._rpc_message_network import APIResponseUpdateNetwork # noqa: F
|
|||
|
||||
from nfv_vim.rpc._rpc_message_sw_update import APIRequestAbortSwUpdateStrategy # noqa: F401
|
||||
from nfv_vim.rpc._rpc_message_sw_update import APIRequestApplySwUpdateStrategy # noqa: F401
|
||||
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 APIRequestDeleteSwUpdateStrategy # noqa: F401
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2016 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -96,6 +96,7 @@ class _RPCMessageType(Constants):
|
|||
|
||||
# Software Update Definitions
|
||||
CREATE_SW_UPDATE_STRATEGY_REQUEST = Constant('create-sw-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_SW_UPDATE_STRATEGY_RESPONSE = Constant('create-sw-update-strategy-response')
|
||||
APPLY_SW_UPDATE_STRATEGY_REQUEST = Constant('apply-sw-update-strategy-request')
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2016 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -143,6 +143,7 @@ class RPCMessageFactory(object):
|
|||
|
||||
from nfv_vim.rpc._rpc_message_sw_update import APIRequestAbortSwUpdateStrategy
|
||||
from nfv_vim.rpc._rpc_message_sw_update import APIRequestApplySwUpdateStrategy
|
||||
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 APIRequestDeleteSwUpdateStrategy
|
||||
|
@ -224,6 +225,7 @@ class RPCMessageFactory(object):
|
|||
|
||||
# Software Update Mapping
|
||||
RPC_MSG_TYPE.CREATE_SW_UPDATE_STRATEGY_REQUEST: APIRequestCreateSwUpdateStrategy,
|
||||
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.APPLY_SW_UPDATE_STRATEGY_REQUEST: APIRequestApplySwUpdateStrategy,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2016 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -84,6 +84,30 @@ class APIRequestCreateSwUpgradeStrategy(APIRequestCreateSwUpdateStrategy):
|
|||
return "create-sw-upgrade-strategy request: %s" % self.deserialize_payload
|
||||
|
||||
|
||||
class APIRequestCreateKubeUpgradeStrategy(APIRequestCreateSwUpdateStrategy):
|
||||
"""
|
||||
RPC API Request Message - Create Kube Upgrade Strategy
|
||||
"""
|
||||
to_version = None
|
||||
|
||||
def __init__(self, msg_version=RPC_MSG_VERSION.VERSION_1_0,
|
||||
msg_type=RPC_MSG_TYPE.CREATE_KUBE_UPGRADE_STRATEGY_REQUEST,
|
||||
msg_result=RPC_MSG_RESULT.SUCCESS):
|
||||
super(APIRequestCreateKubeUpgradeStrategy, self).__init__(
|
||||
msg_version, msg_type, msg_result)
|
||||
|
||||
def serialize_payload(self, msg):
|
||||
super(APIRequestCreateKubeUpgradeStrategy, self).serialize_payload(msg)
|
||||
msg['to_version'] = self.to_version
|
||||
|
||||
def deserialize_payload(self, msg):
|
||||
super(APIRequestCreateKubeUpgradeStrategy, self).deserialize_payload(msg)
|
||||
self.to_version = msg.get('to_version', None)
|
||||
|
||||
def __str__(self):
|
||||
return "create-kube-upgrade-strategy request: %s" % self.deserialize_payload
|
||||
|
||||
|
||||
class APIResponseCreateSwUpdateStrategy(RPCMessage):
|
||||
"""
|
||||
RPC API Response Message - Create Software Update Strategy
|
||||
|
|
|
@ -1,22 +1,34 @@
|
|||
#
|
||||
# Copyright (c) 2015-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
from nfv_common.strategy import * # noqa: F401,F403
|
||||
from nfv_vim.strategy._strategy import FwUpdateStrategy # noqa: F401
|
||||
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_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
|
||||
from nfv_vim.strategy._strategy_steps import DisableHostServicesStep # noqa: F401
|
||||
from nfv_vim.strategy._strategy_steps import FwUpdateAbortHostsStep # noqa: F401
|
||||
from nfv_vim.strategy._strategy_steps import FwUpdateHostsStep # noqa: F401
|
||||
from nfv_vim.strategy._strategy_steps import KubeHostUpgradeControlPlaneStep # noqa: F401
|
||||
from nfv_vim.strategy._strategy_steps import KubeHostUpgradeKubeletStep # noqa: F401
|
||||
from nfv_vim.strategy._strategy_steps import KubeUpgradeCleanupStep # noqa: F401
|
||||
from nfv_vim.strategy._strategy_steps import KubeUpgradeCompleteStep # noqa: F401
|
||||
from nfv_vim.strategy._strategy_steps import KubeUpgradeDownloadImagesStep # noqa: F401
|
||||
from nfv_vim.strategy._strategy_steps import KubeUpgradeNetworkingStep # noqa: F401
|
||||
from nfv_vim.strategy._strategy_steps import KubeUpgradeStartStep # noqa: F401
|
||||
from nfv_vim.strategy._strategy_steps import LockHostsStep # noqa: F401
|
||||
from nfv_vim.strategy._strategy_steps import MigrateInstancesStep # noqa: F401
|
||||
from nfv_vim.strategy._strategy_steps import QueryAlarmsStep # noqa: F401
|
||||
from nfv_vim.strategy._strategy_steps import QueryFwUpdateHostStep # noqa: F401
|
||||
from nfv_vim.strategy._strategy_steps import QueryKubeHostUpgradeStep # noqa: F401
|
||||
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 QueryUpgradeStep # noqa: F401
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -28,6 +28,10 @@ class EventNames(object):
|
|||
DISABLE_HOST_SERVICES_FAILED = Constant('disable-host-services-failed')
|
||||
ENABLE_HOST_SERVICES_FAILED = Constant('enable-host-services-failed')
|
||||
MIGRATE_INSTANCES_FAILED = Constant('migrate-instances-failed')
|
||||
KUBE_HOST_UPGRADE_CONTROL_PLANE_FAILED = \
|
||||
Constant('kube-host-upgrade-control-plane-failed')
|
||||
KUBE_HOST_UPGRADE_KUBELET_FAILED = \
|
||||
Constant('kube-host-upgrade-kubelet-failed')
|
||||
|
||||
|
||||
# Constants
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -34,6 +34,20 @@ 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')
|
||||
KUBE_UPGRADE_QUERY = Constant('kube-upgrade-query')
|
||||
KUBE_UPGRADE_START = Constant('kube-upgrade-start')
|
||||
KUBE_UPGRADE_DOWNLOAD_IMAGES = Constant('kube-upgrade-download-images')
|
||||
KUBE_UPGRADE_FIRST_CONTROL_PLANE = \
|
||||
Constant('kube-upgrade-first-control-plane')
|
||||
KUBE_UPGRADE_NETWORKING = Constant('kube-upgrade-networking')
|
||||
KUBE_UPGRADE_SECOND_CONTROL_PLANE = \
|
||||
Constant('kube-upgrade-second-control-plane')
|
||||
KUBE_UPGRADE_PATCH = Constant('kube-upgrade-patch')
|
||||
KUBE_UPGRADE_KUBELETS_CONTROLLERS = \
|
||||
Constant('kube-upgrade-kubelets-controllers')
|
||||
KUBE_UPGRADE_KUBELETS_WORKERS = Constant('kube-upgrade-kubelets-workers')
|
||||
KUBE_UPGRADE_COMPLETE = Constant('kube-upgrade-complete')
|
||||
KUBE_UPGRADE_CLEANUP = Constant('kube-upgrade-cleanup')
|
||||
|
||||
|
||||
# Constant Instantiation
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2020 Wind River Systems, Inc.
|
||||
# Copyright (c) 2015-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -50,6 +50,18 @@ class StrategyStepNames(Constants):
|
|||
QUERY_UPGRADE = Constant('query-upgrade')
|
||||
DISABLE_HOST_SERVICES = Constant('disable-host-services')
|
||||
ENABLE_HOST_SERVICES = Constant('enable-host-services')
|
||||
APPLY_PATCHES = Constant('apply-patches')
|
||||
QUERY_KUBE_HOST_UPGRADE = Constant('query-kube-host-upgrade')
|
||||
QUERY_KUBE_UPGRADE = Constant('query-kube-upgrade')
|
||||
QUERY_KUBE_VERSIONS = Constant('query-kube-versions')
|
||||
KUBE_UPGRADE_START = Constant('kube-upgrade-start')
|
||||
KUBE_UPGRADE_CLEANUP = Constant('kube-upgrade-cleanup')
|
||||
KUBE_UPGRADE_COMPLETE = Constant('kube-upgrade-complete')
|
||||
KUBE_UPGRADE_DOWNLOAD_IMAGES = Constant('kube-upgrade-download-images')
|
||||
KUBE_UPGRADE_NETWORKING = Constant('kube-upgrade-networking')
|
||||
KUBE_HOST_UPGRADE_CONTROL_PLANE = \
|
||||
Constant('kube-host-upgrade-control-plane')
|
||||
KUBE_HOST_UPGRADE_KUBELET = Constant('kube-host-upgrade-kubelet')
|
||||
|
||||
|
||||
# Constant Instantiation
|
||||
|
@ -1498,6 +1510,7 @@ class QueryAlarmsStep(strategy.StrategyStep):
|
|||
"strictness" % (nfvi_alarm.alarm_id,
|
||||
nfvi_alarm.alarm_uuid))
|
||||
elif nfvi_alarm.alarm_id not in self._ignore_alarms:
|
||||
DLOG.warn("Alarm: %s" % nfvi_alarm.alarm_id)
|
||||
nfvi_alarms.append(nfvi_alarm)
|
||||
else:
|
||||
DLOG.warn("Ignoring alarm %s - uuid %s" %
|
||||
|
@ -2545,11 +2558,737 @@ class EnableHostServicesStep(strategy.StrategyStep):
|
|||
return data
|
||||
|
||||
|
||||
class AbstractStrategyStep(strategy.StrategyStep):
|
||||
|
||||
def __init__(self, step_name, timeout_in_secs):
|
||||
super(AbstractStrategyStep, self).__init__(
|
||||
step_name,
|
||||
timeout_in_secs=timeout_in_secs)
|
||||
|
||||
def from_dict(self, data):
|
||||
"""
|
||||
Returns the step object initialized using the given dictionary
|
||||
"""
|
||||
super(AbstractStrategyStep, self).from_dict(data)
|
||||
return self
|
||||
|
||||
def as_dict(self):
|
||||
"""
|
||||
Represent the step as a dictionary
|
||||
"""
|
||||
data = super(AbstractStrategyStep, self).as_dict()
|
||||
# Next 3 lines are required for all strategy steps and may be
|
||||
# overridden by subclass in some cases
|
||||
data['entity_type'] = ''
|
||||
data['entity_names'] = list()
|
||||
data['entity_uuids'] = list()
|
||||
return data
|
||||
|
||||
|
||||
class ApplySwPatchesStep(AbstractStrategyStep):
|
||||
"""
|
||||
Apply Patches using patch API
|
||||
"""
|
||||
def __init__(self, patches_to_apply):
|
||||
super(ApplySwPatchesStep, self).__init__(
|
||||
STRATEGY_STEP_NAME.APPLY_PATCHES,
|
||||
timeout_in_secs=600)
|
||||
self._patches_to_apply = patches_to_apply
|
||||
|
||||
@coroutine
|
||||
def _api_callback(self):
|
||||
"""
|
||||
Callback for the API method invoked in apply
|
||||
"""
|
||||
response = (yield)
|
||||
DLOG.debug("%s callback response=%s." % (self._name, response))
|
||||
|
||||
if response['completed']:
|
||||
if self.strategy is not None:
|
||||
self.strategy.nfvi_sw_patches = 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, response['reason'])
|
||||
|
||||
def apply(self):
|
||||
"""
|
||||
Apply patches
|
||||
"""
|
||||
from nfv_vim import nfvi
|
||||
|
||||
nfvi.nfvi_sw_mgmt_apply_updates(self._patches_to_apply,
|
||||
self._api_callback())
|
||||
return strategy.STRATEGY_STEP_RESULT.WAIT, ""
|
||||
|
||||
def from_dict(self, data):
|
||||
"""
|
||||
Returns the step object initialized using the given dictionary
|
||||
"""
|
||||
super(ApplySwPatchesStep, self).from_dict(data)
|
||||
# only the names are serialized
|
||||
self._patches_to_apply = data['entity_names']
|
||||
return self
|
||||
|
||||
def as_dict(self):
|
||||
"""
|
||||
Represent the step as a dictionary
|
||||
"""
|
||||
data = super(ApplySwPatchesStep, self).as_dict()
|
||||
data['entity_type'] = 'patches'
|
||||
data['entity_names'] = self._patches_to_apply
|
||||
# there are no entity_uuids
|
||||
return data
|
||||
|
||||
|
||||
class QueryKubeUpgradeStep(AbstractStrategyStep):
|
||||
"""
|
||||
Query Kube Upgrade
|
||||
"""
|
||||
def __init__(self):
|
||||
super(QueryKubeUpgradeStep, self).__init__(
|
||||
STRATEGY_STEP_NAME.QUERY_KUBE_UPGRADE, timeout_in_secs=60)
|
||||
|
||||
@coroutine
|
||||
def _get_kube_upgrade_callback(self):
|
||||
"""
|
||||
Get Kube Upgrade Callback
|
||||
"""
|
||||
response = (yield)
|
||||
DLOG.debug("%s callback response=%s." % (self._name, response))
|
||||
|
||||
if response['completed']:
|
||||
if self.strategy is not None:
|
||||
self.strategy.nfvi_kube_upgrade = 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, response['reason'])
|
||||
|
||||
def apply(self):
|
||||
"""
|
||||
Query Kube Upgrade
|
||||
"""
|
||||
from nfv_vim import nfvi
|
||||
|
||||
DLOG.info("Step (%s) apply." % self._name)
|
||||
nfvi.nfvi_get_kube_upgrade(self._get_kube_upgrade_callback())
|
||||
return strategy.STRATEGY_STEP_RESULT.WAIT, ""
|
||||
|
||||
|
||||
class QueryKubeVersionsStep(AbstractStrategyStep):
|
||||
"""
|
||||
Query Kube Versions
|
||||
This step should be used with its matching QueryKubeVersionsMixin
|
||||
"""
|
||||
def __init__(self):
|
||||
super(QueryKubeVersionsStep, self).__init__(
|
||||
STRATEGY_STEP_NAME.QUERY_KUBE_VERSIONS, timeout_in_secs=60)
|
||||
|
||||
@coroutine
|
||||
def _query_callback(self):
|
||||
"""
|
||||
Get Kube Versions List Callback
|
||||
"""
|
||||
response = (yield)
|
||||
DLOG.debug("%s callback response=%s." % (self._name, response))
|
||||
|
||||
if response['completed']:
|
||||
if self.strategy is not None:
|
||||
self.strategy.nfvi_kube_versions_list = 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, response['reason'])
|
||||
|
||||
def apply(self):
|
||||
"""
|
||||
Query Kube Versions List
|
||||
"""
|
||||
from nfv_vim import nfvi
|
||||
|
||||
nfvi.nfvi_get_kube_version_list(self._query_callback())
|
||||
return strategy.STRATEGY_STEP_RESULT.WAIT, ""
|
||||
|
||||
|
||||
class QueryKubeHostUpgradeStep(AbstractStrategyStep):
|
||||
"""
|
||||
Query Kube Host Upgrade list
|
||||
"""
|
||||
def __init__(self):
|
||||
super(QueryKubeHostUpgradeStep, self).__init__(
|
||||
STRATEGY_STEP_NAME.QUERY_KUBE_HOST_UPGRADE, timeout_in_secs=60)
|
||||
|
||||
@coroutine
|
||||
def _get_kube_host_upgrade_list_callback(self):
|
||||
"""
|
||||
Get Kube Host Upgrade List Callback
|
||||
"""
|
||||
response = (yield)
|
||||
DLOG.debug("%s callback response=%s." % (self._name, response))
|
||||
|
||||
if response['completed']:
|
||||
if self.strategy is not None:
|
||||
self.strategy.nfvi_kube_host_upgrade_list = \
|
||||
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, response['reason'])
|
||||
|
||||
def apply(self):
|
||||
"""
|
||||
Query Kube Host Upgrade List
|
||||
"""
|
||||
from nfv_vim import nfvi
|
||||
nfvi.nfvi_get_kube_host_upgrade_list(
|
||||
self._get_kube_host_upgrade_list_callback())
|
||||
return strategy.STRATEGY_STEP_RESULT.WAIT, ""
|
||||
|
||||
|
||||
class AbstractKubeUpgradeStep(AbstractStrategyStep):
|
||||
|
||||
def __init__(self,
|
||||
step_name,
|
||||
success_state,
|
||||
fail_state,
|
||||
timeout_in_secs=600):
|
||||
super(AbstractKubeUpgradeStep, self).__init__(step_name,
|
||||
timeout_in_secs)
|
||||
# These two attributes are not persisted
|
||||
self._wait_time = 0
|
||||
self._query_inprogress = False
|
||||
# success and fail state validators are persisted
|
||||
self._success_state = success_state
|
||||
self._fail_state = fail_state
|
||||
|
||||
@coroutine
|
||||
def _get_kube_upgrade_callback(self):
|
||||
"""Get Upgrade Callback"""
|
||||
response = (yield)
|
||||
DLOG.debug("(%s) callback response=%s." % (self._name, response))
|
||||
|
||||
self._query_inprogress = False
|
||||
if response['completed']:
|
||||
if self.strategy is None:
|
||||
# there is no longer a strategy. abort.
|
||||
result = strategy.STRATEGY_STEP_RESULT.FAILED
|
||||
self.stage.step_complete(result, 'strategy no longer exists')
|
||||
|
||||
kube_upgrade_obj = response['result-data']
|
||||
# replace the object in the strategy with the most recent object
|
||||
self.strategy.nfvi_kube_upgrade = kube_upgrade_obj
|
||||
|
||||
# break out of the loop if fail or success states match
|
||||
if kube_upgrade_obj.state == self._success_state:
|
||||
DLOG.debug("(%s) successfully reached (%s)."
|
||||
% (self._name, self._success_state))
|
||||
result = strategy.STRATEGY_STEP_RESULT.SUCCESS
|
||||
self.stage.step_complete(result, "")
|
||||
elif (self._fail_state is not None
|
||||
and kube_upgrade_obj.state == self._fail_state):
|
||||
DLOG.warn("(%s) encountered failure state(%s)."
|
||||
% (self._name, self._fail_state))
|
||||
result = strategy.STRATEGY_STEP_RESULT.FAILED
|
||||
self.stage.step_complete(
|
||||
result,
|
||||
'(%s) failed:(%s)' % (self._name, self._fail_state)
|
||||
)
|
||||
else:
|
||||
# Keep waiting for upgrade to reach success or fail state
|
||||
# timeout will occur if it is never reached.
|
||||
DLOG.debug("(%s) in state (%s) waiting for (%s) or (%s)."
|
||||
% (self._name,
|
||||
kube_upgrade_obj.state,
|
||||
self._success_state,
|
||||
self._fail_state))
|
||||
pass
|
||||
else:
|
||||
result = strategy.STRATEGY_STEP_RESULT.FAILED
|
||||
self.stage.step_complete(result, response['reason'])
|
||||
|
||||
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 60 seconds before checking upgrade for first time
|
||||
if 60 <= secs_expired and not self._query_inprogress:
|
||||
self._query_inprogress = True
|
||||
nfvi.nfvi_get_kube_upgrade(self._get_kube_upgrade_callback())
|
||||
return True
|
||||
return False
|
||||
|
||||
def from_dict(self, data):
|
||||
"""
|
||||
Returns the step object initialized using the given dictionary
|
||||
"""
|
||||
super(AbstractKubeUpgradeStep, self).from_dict(data)
|
||||
# these two attributes are not persisted
|
||||
self._wait_time = 0
|
||||
self._query_inprogress = False
|
||||
# validation states are persisted
|
||||
self._success_state = data['success_state']
|
||||
self._fail_state = data['fail_state']
|
||||
return self
|
||||
|
||||
def as_dict(self):
|
||||
"""
|
||||
Represent the kube upgrade step as a dictionary
|
||||
"""
|
||||
data = super(AbstractKubeUpgradeStep, self).as_dict()
|
||||
data['success_state'] = self._success_state
|
||||
data['fail_state'] = self._fail_state
|
||||
return data
|
||||
|
||||
|
||||
class KubeUpgradeStartStep(AbstractKubeUpgradeStep):
|
||||
"""Kube Upgrade Start - Strategy Step"""
|
||||
|
||||
def __init__(self, to_version, force=False):
|
||||
|
||||
from nfv_vim import nfvi
|
||||
|
||||
super(KubeUpgradeStartStep, self).__init__(
|
||||
STRATEGY_STEP_NAME.KUBE_UPGRADE_START,
|
||||
nfvi.objects.v1.KUBE_UPGRADE_STATE.KUBE_UPGRADE_STARTED,
|
||||
None) # there is no failure state if upgrade-start fails
|
||||
# next 2 attributes must be persisted through from_dict/as_dict
|
||||
self._to_version = to_version
|
||||
self._force = force
|
||||
|
||||
def from_dict(self, data):
|
||||
"""
|
||||
Returns the step object initialized using the given dictionary
|
||||
"""
|
||||
super(KubeUpgradeStartStep, self).from_dict(data)
|
||||
self._to_version = data['to_version']
|
||||
self._force = data['force']
|
||||
return self
|
||||
|
||||
def as_dict(self):
|
||||
"""
|
||||
Represent the kube upgrade step as a dictionary
|
||||
"""
|
||||
data = super(KubeUpgradeStartStep, self).as_dict()
|
||||
data['to_version'] = self._to_version
|
||||
data['force'] = self._force
|
||||
return data
|
||||
|
||||
@coroutine
|
||||
def _response_callback(self):
|
||||
"""Kube Upgrade Start - Callback"""
|
||||
|
||||
response = (yield)
|
||||
DLOG.debug("%s callback response=%s." % (self._name, response))
|
||||
|
||||
if response['completed']:
|
||||
if self.strategy is not None:
|
||||
self.strategy.nfvi_kube_upgrade = response['result-data']
|
||||
# We do not set 'success' here, let the handle_event do this
|
||||
else:
|
||||
result = strategy.STRATEGY_STEP_RESULT.FAILED
|
||||
self.stage.step_complete(result, response['reason'])
|
||||
|
||||
def apply(self):
|
||||
"""Kube Upgrade Start"""
|
||||
|
||||
from nfv_vim import nfvi
|
||||
|
||||
alarm_ignore_list = ["900.401", ] # ignore the auto apply alarm
|
||||
nfvi.nfvi_kube_upgrade_start(self._to_version,
|
||||
self._force,
|
||||
alarm_ignore_list,
|
||||
self._response_callback())
|
||||
return strategy.STRATEGY_STEP_RESULT.WAIT, ""
|
||||
|
||||
|
||||
class KubeUpgradeCleanupStep(AbstractKubeUpgradeStep):
|
||||
"""Kube Upgrade Cleanup - Strategy Step"""
|
||||
|
||||
def __init__(self):
|
||||
super(KubeUpgradeCleanupStep, self).__init__(
|
||||
STRATEGY_STEP_NAME.KUBE_UPGRADE_CLEANUP,
|
||||
None, # there is no success state for this cleanup activity
|
||||
None) # there is no failure state for this cleanup activity
|
||||
|
||||
@coroutine
|
||||
def _response_callback(self):
|
||||
"""Kube Upgrade Cleanup - Callback"""
|
||||
|
||||
response = (yield)
|
||||
DLOG.debug("%s callback response=%s." % (self._name, response))
|
||||
|
||||
if response['completed']:
|
||||
if self.strategy is not None:
|
||||
# cleanup deletes the kube upgrade, clear it from the strategy
|
||||
self.strategy.nfvi_kube_upgrade = None
|
||||
result = strategy.STRATEGY_STEP_RESULT.SUCCESS
|
||||
self.stage.step_complete(result, "")
|
||||
else:
|
||||
result = strategy.STRATEGY_STEP_RESULT.FAILED
|
||||
self.stage.step_complete(result, response['reason'])
|
||||
|
||||
def apply(self):
|
||||
"""Kube Upgrade Cleanup"""
|
||||
|
||||
from nfv_vim import nfvi
|
||||
|
||||
nfvi.nfvi_kube_upgrade_cleanup(self._response_callback())
|
||||
return strategy.STRATEGY_STEP_RESULT.WAIT, ""
|
||||
|
||||
|
||||
class KubeUpgradeCompleteStep(AbstractKubeUpgradeStep):
|
||||
"""Kube Upgrade Complete - Strategy Step"""
|
||||
|
||||
def __init__(self):
|
||||
from nfv_vim import nfvi
|
||||
super(KubeUpgradeCompleteStep, self).__init__(
|
||||
STRATEGY_STEP_NAME.KUBE_UPGRADE_COMPLETE,
|
||||
nfvi.objects.v1.KUBE_UPGRADE_STATE.KUBE_UPGRADE_COMPLETE,
|
||||
None) # there is no failure state for upgrade-complete
|
||||
|
||||
@coroutine
|
||||
def _response_callback(self):
|
||||
"""Kube Upgrade Complete - Callback"""
|
||||
|
||||
response = (yield)
|
||||
DLOG.debug("%s callback response=%s." % (self._name, response))
|
||||
|
||||
if response['completed']:
|
||||
if self.strategy is not None:
|
||||
self.strategy.nfvi_kube_upgrade = response['result-data']
|
||||
else:
|
||||
result = strategy.STRATEGY_STEP_RESULT.FAILED
|
||||
self.stage.step_complete(result, response['reason'])
|
||||
|
||||
def apply(self):
|
||||
"""Kube Upgrade Complete """
|
||||
|
||||
from nfv_vim import nfvi
|
||||
|
||||
nfvi.nfvi_kube_upgrade_complete(self._response_callback())
|
||||
return strategy.STRATEGY_STEP_RESULT.WAIT, ""
|
||||
|
||||
|
||||
class KubeUpgradeDownloadImagesStep(AbstractKubeUpgradeStep):
|
||||
"""Kube Upgrade Download Images - Strategy Step"""
|
||||
|
||||
def __init__(self):
|
||||
from nfv_vim import nfvi
|
||||
super(KubeUpgradeDownloadImagesStep, self).__init__(
|
||||
STRATEGY_STEP_NAME.KUBE_UPGRADE_DOWNLOAD_IMAGES,
|
||||
nfvi.objects.v1.KUBE_UPGRADE_STATE.KUBE_UPGRADE_DOWNLOADED_IMAGES,
|
||||
nfvi.objects.v1.KUBE_UPGRADE_STATE.KUBE_UPGRADE_DOWNLOADING_IMAGES_FAILED)
|
||||
|
||||
@coroutine
|
||||
def _response_callback(self):
|
||||
"""Kube Upgrade Download Images - Callback"""
|
||||
|
||||
response = (yield)
|
||||
DLOG.debug("%s callback response=%s." % (self._name, response))
|
||||
|
||||
if response['completed']:
|
||||
if self.strategy is not None:
|
||||
self.strategy.nfvi_kube_upgrade = response['result-data']
|
||||
else:
|
||||
result = strategy.STRATEGY_STEP_RESULT.FAILED
|
||||
self.stage.step_complete(result, response['reason'])
|
||||
|
||||
def apply(self):
|
||||
"""Kube Upgrade Download Images """
|
||||
|
||||
from nfv_vim import nfvi
|
||||
|
||||
nfvi.nfvi_kube_upgrade_download_images(self._response_callback())
|
||||
return strategy.STRATEGY_STEP_RESULT.WAIT, ""
|
||||
|
||||
|
||||
class KubeUpgradeNetworkingStep(AbstractKubeUpgradeStep):
|
||||
"""Kube Upgrade Networking - Strategy Step"""
|
||||
|
||||
def __init__(self):
|
||||
from nfv_vim import nfvi
|
||||
super(KubeUpgradeNetworkingStep, self).__init__(
|
||||
STRATEGY_STEP_NAME.KUBE_UPGRADE_NETWORKING,
|
||||
nfvi.objects.v1.KUBE_UPGRADE_STATE.KUBE_UPGRADED_NETWORKING,
|
||||
nfvi.objects.v1.KUBE_UPGRADE_STATE.KUBE_UPGRADING_NETWORKING_FAILED)
|
||||
|
||||
@coroutine
|
||||
def _response_callback(self):
|
||||
"""Kube Upgrade Networking - Callback"""
|
||||
|
||||
response = (yield)
|
||||
DLOG.debug("%s callback response=%s." % (self._name, response))
|
||||
|
||||
if response['completed']:
|
||||
if self.strategy is not None:
|
||||
self.strategy.nfvi_kube_upgrade = response['result-data']
|
||||
else:
|
||||
result = strategy.STRATEGY_STEP_RESULT.FAILED
|
||||
self.stage.step_complete(result, response['reason'])
|
||||
|
||||
def apply(self):
|
||||
"""Kube Upgrade Networking"""
|
||||
|
||||
from nfv_vim import nfvi
|
||||
|
||||
nfvi.nfvi_kube_upgrade_networking(self._response_callback())
|
||||
return strategy.STRATEGY_STEP_RESULT.WAIT, ""
|
||||
|
||||
|
||||
class AbstractKubeHostUpgradeStep(AbstractKubeUpgradeStep):
|
||||
"""Kube Upgrade Host - Abtsract Strategy Step
|
||||
|
||||
This operation issues a host command, which updates the kube upgrade object
|
||||
"""
|
||||
def __init__(self,
|
||||
host,
|
||||
force,
|
||||
step_name,
|
||||
success_state,
|
||||
fail_state,
|
||||
timeout_in_secs=600):
|
||||
super(AbstractKubeHostUpgradeStep, self).__init__(
|
||||
step_name,
|
||||
success_state,
|
||||
fail_state,
|
||||
timeout_in_secs=timeout_in_secs)
|
||||
self._force = force
|
||||
# This class accepts only a single host
|
||||
# but serializes as a list of hosts (list size of one)
|
||||
self._hosts = list()
|
||||
self._host_names = list()
|
||||
self._host_uuids = list()
|
||||
self._hosts.append(host)
|
||||
self._host_names.append(host.name)
|
||||
self._host_uuids.append(host.uuid)
|
||||
|
||||
def from_dict(self, data):
|
||||
"""
|
||||
Returns the step object initialized using the given dictionary
|
||||
"""
|
||||
super(AbstractKubeHostUpgradeStep, self).from_dict(data)
|
||||
self._force = data['force']
|
||||
self._hosts = list()
|
||||
self._host_uuids = list()
|
||||
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 step as a dictionary
|
||||
"""
|
||||
data = super(AbstractKubeHostUpgradeStep, self).as_dict()
|
||||
data['force'] = self._force
|
||||
data['entity_type'] = 'hosts'
|
||||
data['entity_names'] = self._host_names
|
||||
data['entity_uuids'] = self._host_uuids
|
||||
return data
|
||||
|
||||
|
||||
class KubeHostUpgradeControlPlaneStep(AbstractKubeHostUpgradeStep):
|
||||
"""Kube Host Upgrade Control Plane - Strategy Step
|
||||
|
||||
This operation issues a host command, which updates the kube upgrade object
|
||||
"""
|
||||
|
||||
def __init__(self, host, force, target_state, target_failure_state):
|
||||
super(KubeHostUpgradeControlPlaneStep, self).__init__(
|
||||
host,
|
||||
force,
|
||||
STRATEGY_STEP_NAME.KUBE_HOST_UPGRADE_CONTROL_PLANE,
|
||||
target_state,
|
||||
target_failure_state,
|
||||
timeout_in_secs=600)
|
||||
|
||||
def handle_event(self, event, event_data=None):
|
||||
"""
|
||||
Handle Host events - does not query kube host upgrade list but
|
||||
instead queries kube host upgrade directly.
|
||||
"""
|
||||
DLOG.debug("Step (%s) handle event (%s)." % (self._name, event))
|
||||
|
||||
if event == STRATEGY_EVENT.KUBE_HOST_UPGRADE_CONTROL_PLANE_FAILED:
|
||||
host = event_data
|
||||
if host is not None and host.name in self._host_names:
|
||||
result = strategy.STRATEGY_STEP_RESULT.FAILED
|
||||
self.stage.step_complete(
|
||||
result,
|
||||
"kube host upgrade control plane (%s) failed" % host.name)
|
||||
return True
|
||||
# return handle_event of parent class
|
||||
return super(KubeHostUpgradeControlPlaneStep, self).handle_event(
|
||||
event, event_data=event_data)
|
||||
|
||||
def apply(self):
|
||||
"""Kube Host Upgrade Control Plane"""
|
||||
|
||||
from nfv_vim import directors
|
||||
|
||||
DLOG.info("Step (%s) apply to hostnames (%s)."
|
||||
% (self._name, self._host_names))
|
||||
host_director = directors.get_host_director()
|
||||
operation = \
|
||||
host_director.kube_upgrade_hosts_control_plane(self._host_names,
|
||||
self._force)
|
||||
|
||||
if operation.is_inprogress():
|
||||
return strategy.STRATEGY_STEP_RESULT.WAIT, ""
|
||||
elif operation.is_failed():
|
||||
return strategy.STRATEGY_STEP_RESULT.FAILED, operation.reason
|
||||
|
||||
return strategy.STRATEGY_STEP_RESULT.SUCCESS, ""
|
||||
|
||||
|
||||
class KubeHostUpgradeKubeletStep(AbstractKubeHostUpgradeStep):
|
||||
"""Kube Host Upgrade Kubelet - Strategy Step
|
||||
|
||||
This operation issues a host command, which indirectly updates the kube
|
||||
upgrade object, however additional calls to other hosts do not change it.
|
||||
This step should only be invoked on a locked host.
|
||||
"""
|
||||
|
||||
def __init__(self, host, force):
|
||||
super(KubeHostUpgradeKubeletStep, self).__init__(
|
||||
host,
|
||||
force,
|
||||
STRATEGY_STEP_NAME.KUBE_HOST_UPGRADE_KUBELET,
|
||||
None, # there is no kube upgrade success state for kubelets
|
||||
None, # there is no kube upgrade failure state for kubelets
|
||||
timeout_in_secs=900) # kubelet takes longer than control plane
|
||||
|
||||
@coroutine
|
||||
def _get_kube_host_upgrade_list_callback(self):
|
||||
"""Get Kube Host Upgrade List Callback"""
|
||||
|
||||
response = (yield)
|
||||
DLOG.debug("(%s) callback response=%s." % (self._name, response))
|
||||
|
||||
self._query_inprogress = False
|
||||
if response['completed']:
|
||||
self.strategy.nfvi_kube_host_upgrade_list = response['result-data']
|
||||
|
||||
host_count = 0
|
||||
match_count = 0
|
||||
for host_uuid in self._host_uuids:
|
||||
for k_host in self.strategy.nfvi_kube_host_upgrade_list:
|
||||
if k_host.host_uuid == host_uuid:
|
||||
if k_host.kubelet_version == self.strategy.to_version:
|
||||
match_count += 1
|
||||
host_count += 1
|
||||
# break out of inner loop, since uuids match
|
||||
break
|
||||
if host_count == len(self._host_uuids):
|
||||
# this is a pointless break
|
||||
break
|
||||
if match_count == len(self._host_uuids):
|
||||
result = strategy.STRATEGY_STEP_RESULT.SUCCESS
|
||||
self.stage.step_complete(result, "")
|
||||
else:
|
||||
# keep waiting for kubelet state to change
|
||||
pass
|
||||
else:
|
||||
result = strategy.STRATEGY_STEP_RESULT.FAILED
|
||||
self.stage.step_complete(result, response['reason'])
|
||||
|
||||
def handle_event(self, event, event_data=None):
|
||||
"""
|
||||
Handle Host events - queries kube host upgrade list
|
||||
Override to bypass checking for kube upgrade state.
|
||||
"""
|
||||
from nfv_vim import nfvi
|
||||
|
||||
DLOG.debug("Step (%s) handle event (%s)." % (self._name, event))
|
||||
|
||||
if event == STRATEGY_EVENT.KUBE_HOST_UPGRADE_KUBELET_FAILED:
|
||||
host = event_data
|
||||
if host is not None and host.name in self._host_names:
|
||||
result = strategy.STRATEGY_STEP_RESULT.FAILED
|
||||
self.stage.step_complete(
|
||||
result,
|
||||
"kube host upgrade kubelet (%s) failed" % host.name)
|
||||
return True
|
||||
elif 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 60 seconds before checking upgrade for first time
|
||||
if 60 <= secs_expired and not self._query_inprogress:
|
||||
self._query_inprogress = True
|
||||
nfvi.nfvi_get_kube_host_upgrade_list(
|
||||
self._get_kube_host_upgrade_list_callback())
|
||||
return True
|
||||
return False
|
||||
|
||||
def apply(self):
|
||||
"""Kube Upgrade Kubelet"""
|
||||
|
||||
from nfv_vim import directors
|
||||
|
||||
DLOG.info("Step (%s) apply to hostnames (%s)."
|
||||
% (self._name, self._host_names))
|
||||
host_director = directors.get_host_director()
|
||||
operation = \
|
||||
host_director.kube_upgrade_hosts_kubelet(self._host_names,
|
||||
self._force)
|
||||
|
||||
if operation.is_inprogress():
|
||||
return strategy.STRATEGY_STEP_RESULT.WAIT, ""
|
||||
elif operation.is_failed():
|
||||
return strategy.STRATEGY_STEP_RESULT.FAILED, operation.reason
|
||||
|
||||
return strategy.STRATEGY_STEP_RESULT.SUCCESS, ""
|
||||
|
||||
|
||||
def strategy_step_rebuild_from_dict(data):
|
||||
"""
|
||||
Returns the strategy step object initialized using the given dictionary
|
||||
"""
|
||||
if STRATEGY_STEP_NAME.SYSTEM_STABILIZE == data['name']:
|
||||
rebuild_map = {
|
||||
STRATEGY_STEP_NAME.APPLY_PATCHES: ApplySwPatchesStep,
|
||||
STRATEGY_STEP_NAME.KUBE_HOST_UPGRADE_CONTROL_PLANE:
|
||||
KubeHostUpgradeControlPlaneStep,
|
||||
STRATEGY_STEP_NAME.KUBE_HOST_UPGRADE_KUBELET:
|
||||
KubeHostUpgradeKubeletStep,
|
||||
STRATEGY_STEP_NAME.KUBE_UPGRADE_CLEANUP: KubeUpgradeCleanupStep,
|
||||
STRATEGY_STEP_NAME.KUBE_UPGRADE_COMPLETE: KubeUpgradeCompleteStep,
|
||||
STRATEGY_STEP_NAME.KUBE_UPGRADE_DOWNLOAD_IMAGES:
|
||||
KubeUpgradeDownloadImagesStep,
|
||||
STRATEGY_STEP_NAME.KUBE_UPGRADE_NETWORKING: KubeUpgradeNetworkingStep,
|
||||
STRATEGY_STEP_NAME.KUBE_UPGRADE_START: KubeUpgradeStartStep,
|
||||
STRATEGY_STEP_NAME.QUERY_KUBE_HOST_UPGRADE: QueryKubeHostUpgradeStep,
|
||||
STRATEGY_STEP_NAME.QUERY_KUBE_UPGRADE: QueryKubeUpgradeStep,
|
||||
STRATEGY_STEP_NAME.QUERY_KUBE_VERSIONS: QueryKubeVersionsStep,
|
||||
}
|
||||
obj_type = rebuild_map.get(data['name'])
|
||||
if obj_type is not None:
|
||||
step_obj = object.__new__(obj_type)
|
||||
|
||||
elif STRATEGY_STEP_NAME.SYSTEM_STABILIZE == data['name']:
|
||||
step_obj = object.__new__(SystemStabilizeStep)
|
||||
|
||||
elif STRATEGY_STEP_NAME.UNLOCK_HOSTS == data['name']:
|
||||
|
|
|
@ -63,7 +63,7 @@ output-format=text
|
|||
files-output=no
|
||||
|
||||
# Tells whether to display a full report or only the messages
|
||||
reports=no
|
||||
reports=yes
|
||||
|
||||
# Python expression which should return a note less than 10 (10 is the highest
|
||||
# note). You have access to the variables errors warning, statement which
|
||||
|
|
Loading…
Reference in New Issue