Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[sonic-package-manager] support warm/fast reboot for extension packages #1554

Merged
merged 75 commits into from
Jul 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
2356869
[sonic-installer] migrate SONiC packages
stepanblyschak Nov 3, 2020
ece3845
fix temp dir path for chroot
stepanblyschak Nov 3, 2020
8bc75a7
fix for install of already installed image
stepanblyschak Nov 3, 2020
e72f540
move constants to the top
stepanblyschak Dec 15, 2020
1a6d5d9
Merge branch 'master' of github.com:azure/sonic-utilities into sonic-…
stepanblyschak Jan 5, 2021
be4f089
[sonic_installer] migrate packages from old docker library
stepanblyschak Jan 21, 2021
2240308
Merge branch 'master' of github.com:azure/sonic-utilities into sonic-…
stepanblyschak Mar 18, 2021
9fd283d
remove unused imports
stepanblyschak Mar 18, 2021
0cbaa3e
fix redefining path
stepanblyschak Mar 19, 2021
1a99797
[sonic-package-manager] add new utility to manage SONiC packages
stepanblyschak Mar 23, 2021
a80ecb0
Merge branch 'sonic-packages-migration' into spm
stepanblyschak Mar 23, 2021
06dfd30
add help for some options
stepanblyschak Mar 23, 2021
725210d
add command line reference for sonic-package-manager
stepanblyschak Mar 23, 2021
f2ee39f
fix upgrade command missing argument
stepanblyschak Mar 23, 2021
7bf937e
warm-reboot support for sonic packages
stepanblyschak Mar 25, 2021
c724569
iteritems -> items
stepanblyschak Mar 25, 2021
ac011a3
Merge branch 'spm' into spm_warm
stepanblyschak Mar 25, 2021
3dc793f
fix issue in metadata dict generation
stepanblyschak Mar 25, 2021
4e4a9ea
Merge branch 'spm' of github.com:stepanblyschak/sonic-utilities into …
stepanblyschak Mar 25, 2021
ea14867
fix creator with service name
stepanblyschak Mar 25, 2021
faeadcf
default value for component constraint
stepanblyschak Mar 25, 2021
cd7d387
Merge branch 'spm' into spm_warm
stepanblyschak Mar 25, 2021
31138d0
fix passing installed_packages
stepanblyschak Mar 26, 2021
ae1ce45
Update doc/Command-Reference.md
stepanblyschak Mar 29, 2021
5c045e0
use defaultdict
stepanblyschak Mar 30, 2021
a1a97f9
fix internal review comments
stepanblyschak Mar 30, 2021
7a6c8d1
fix internal review comments
stepanblyschak Mar 30, 2021
c4b4225
use get_installed_packages_list() function
stepanblyschak Mar 31, 2021
f32d038
dont fail uninstall when no package in installed list
stepanblyschak Mar 31, 2021
83f2af6
drop support for monit as monit is getting deprecated
stepanblyschak Apr 1, 2021
d31497a
fix manifest representation
stepanblyschak Apr 1, 2021
c2eacdf
fix LGTM warning
stepanblyschak Apr 1, 2021
801ff85
Merge branch 'master' into spm
stepanblyschak Apr 8, 2021
f5ba246
fix review comments
stepanblyschak Apr 9, 2021
2dee5c6
fix review comments
stepanblyschak Apr 14, 2021
08c9c6d
[sonic_package_manager] add reset command
stepanblyschak Apr 15, 2021
42a2665
Merge branch 'master' into spm
stepanblyschak Apr 15, 2021
413b44f
[doc] fix formatting
stepanblyschak Apr 16, 2021
78afedd
Merge branch 'spm' of github.com:stepanblyschak/sonic-utilities into spm
stepanblyschak Apr 16, 2021
f101f1f
install takes a digest or tag as well
stepanblyschak Apr 16, 2021
4d03aa8
resolve review comments
stepanblyschak Apr 20, 2021
180eae3
remove config when uninstalling
stepanblyschak Apr 20, 2021
3b98489
fix lgtm error
stepanblyschak Apr 20, 2021
3280b5b
Update doc/Command-Reference.md
stepanblyschak Apr 21, 2021
21ae66b
Update doc/Command-Reference.md
stepanblyschak Apr 21, 2021
5548976
Update doc/Command-Reference.md
stepanblyschak Apr 21, 2021
5a2675d
Update doc/Command-Reference.md
stepanblyschak Apr 21, 2021
68f90f5
Update doc/Command-Reference.md
stepanblyschak Apr 21, 2021
e7f1c59
Update doc/Command-Reference.md
stepanblyschak Apr 21, 2021
ae5bad9
Update doc/Command-Reference.md
stepanblyschak Apr 21, 2021
909079a
Update doc/Command-Reference.md
stepanblyschak Apr 21, 2021
a394b27
Update doc/Command-Reference.md
stepanblyschak Apr 21, 2021
9653c61
Update doc/Command-Reference.md
stepanblyschak Apr 21, 2021
0e96ddb
Update doc/Command-Reference.md
stepanblyschak Apr 21, 2021
9090a47
Update doc/Command-Reference.md
stepanblyschak Apr 21, 2021
b2eeb59
Update doc/Command-Reference.md
stepanblyschak Apr 21, 2021
e765d5d
review comments
stepanblyschak Apr 21, 2021
24fb439
Merge branch 'spm' of github.com:stepanblyschak/sonic-utilities into spm
stepanblyschak Apr 21, 2021
fd46c34
fix upgrade rollback
stepanblyschak Apr 22, 2021
86bf53f
address review comments
stepanblyschak Apr 23, 2021
1ace0e1
fix command line options for install/upgrade
stepanblyschak Apr 26, 2021
6feda36
fix bug when have components constraints
stepanblyschak Apr 26, 2021
a2f7649
Merge branch 'master' into spm
stepanblyschak Apr 26, 2021
0d5dfcf
Fix review comments
stepanblyschak Apr 28, 2021
4c2f986
Merge branch 'spm' of github.com:stepanblyschak/sonic-utilities into spm
stepanblyschak Apr 28, 2021
3c1b429
Merge branch 'spm' of github.com:stepanblyschak/sonic-utilities into …
stepanblyschak Apr 30, 2021
e91ff81
fix script
stepanblyschak Apr 30, 2021
b87e6fd
Merge branch 'master' of github.com:azure/sonic-utilities into spm_warm
stepanblyschak Apr 30, 2021
62e2646
fix unresolved conftest.py
stepanblyschak Apr 30, 2021
79cabb2
fix unresolved test_service_creator.py
stepanblyschak Apr 30, 2021
a23fe44
fix lgtm warning
stepanblyschak Apr 30, 2021
f4be579
fix lgtm warning
stepanblyschak Apr 30, 2021
53111a8
Merge branch 'master' of github.com:azure/sonic-utilities into spm_warm
stepanblyschak May 13, 2021
0ba3cf4
improve manifest types validation
stepanblyschak May 13, 2021
1554f00
fix docstrings
stepanblyschak May 13, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1993,20 +1993,28 @@ def warm_restart(ctx, redis_unix_socket_path):
ctx.obj = {'db': config_db, 'state_db': state_db, 'prefix': prefix}

@warm_restart.command('enable')
@click.argument('module', metavar='<module>', default='system', required=False, type=click.Choice(["system", "swss", "bgp", "teamd"]))
@click.argument('module', metavar='<module>', default='system', required=False)
@click.pass_context
def warm_restart_enable(ctx, module):
state_db = ctx.obj['state_db']
config_db = ctx.obj['db']
feature_table = config_db.get_table('FEATURE')
if module != 'system' and module not in feature_table:
exit('Feature {} is unknown'.format(module))
prefix = ctx.obj['prefix']
_hash = '{}{}'.format(prefix, module)
state_db.set(state_db.STATE_DB, _hash, 'enable', 'true')
state_db.close(state_db.STATE_DB)

@warm_restart.command('disable')
@click.argument('module', metavar='<module>', default='system', required=False, type=click.Choice(["system", "swss", "bgp", "teamd"]))
@click.argument('module', metavar='<module>', default='system', required=False)
@click.pass_context
def warm_restart_enable(ctx, module):
state_db = ctx.obj['state_db']
config_db = ctx.obj['db']
feature_table = config_db.get_table('FEATURE')
if module != 'system' and module not in feature_table:
exit('Feature {} is unknown'.format(module))
prefix = ctx.obj['prefix']
_hash = '{}{}'.format(prefix, module)
state_db.set(state_db.STATE_DB, _hash, 'enable', 'false')
Expand Down
119 changes: 55 additions & 64 deletions scripts/fast-reboot
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ WARM_DIR=/host/warmboot
REDIS_FILE=dump.rdb
REBOOT_SCRIPT_NAME=$(basename $0)
REBOOT_TYPE="${REBOOT_SCRIPT_NAME}"
SHUTDOWN_ORDER_FILE="/etc/sonic/${REBOOT_TYPE}_order"
VERBOSE=no
FORCE=no
IGNORE_ASIC=no
Expand Down Expand Up @@ -567,82 +568,72 @@ if [ -x ${LOG_SSD_HEALTH} ]; then
fi
# Kill nat docker after saving the conntrack table
debug "Stopping nat ..."
/usr/local/bin/dump_nat_entries.py
docker kill nat > /dev/null || true
systemctl stop nat
debug "Stopped nat ..."
# Kill radv before stopping BGP service to prevent announcing our departure.
debug "Stopping radv service..."
systemctl stop radv
debug "Stopped radv service..."
# Kill bgpd to start the bgp graceful restart procedure
debug "Stopping bgp ..."
systemctl stop bgp
debug "Stopped bgp ..."
# Kill sflow docker
debug "Stopping sflow ..."
container kill sflow &> /dev/null || debug "Docker sflow is not running ($?) ..."
systemctl stop sflow
debug "Stopped sflow ..."
# Kill lldp, otherwise it sends informotion about reboot.
# We call `docker kill lldp` to ensure the container stops as quickly as possible,
# then immediately call `systemctl stop lldp` to prevent the service from
# restarting the container automatically.
container kill lldp &> /dev/null || debug "Docker lldp is not running ($?) ..."
systemctl stop lldp
if [[ "$REBOOT_TYPE" = "fast-reboot" ]]; then
debug "Stopping teamd ..."
systemctl stop teamd
debug "Stopped teamd ..."
if [[ -f ${SHUTDOWN_ORDER_FILE} ]]; then
SERVICES_TO_STOP="$(cat ${SHUTDOWN_ORDER_FILE})"
else
# TODO: to be removed once sonic-buildimage change is in
if [[ "${REBOOT_TYPE}" == "fast-reboot" ]]; then
SERVICES_TO_STOP="nat radv bgp sflow lldp swss teamd syncd"
elif [[ "${REBOOT_TYPE}" == "fastfast-reboot" || "${REBOOT_TYPE}" == "warm-reboot" ]]; then
SERVICES_TO_STOP="nat radv bgp sflow lldp teamd swss syncd"
else
error "Unexpected reboot type ${REBOOT_TYPE}"
exit $EXIT_FAILURE
fi
fi
debug "Stopping swss service ..."
systemctl stop swss
debug "Stopped swss service ..."
for service in ${SERVICES_TO_STOP}; do
debug "Stopping ${service} ..."
if [[ "$REBOOT_TYPE" = "warm-reboot" || "$REBOOT_TYPE" = "fastfast-reboot" ]]; then
# Pre-shutdown syncd
initialize_pre_shutdown
# TODO: These exceptions for nat, sflow, lldp
# have to be coded in corresponding service scripts
if [[ "x$sonic_asic_type" == x"mellanox" ]]; then
check_issu_bank_file
if [[ "${service}" = "nat" ]]; then
/usr/local/bin/dump_nat_entries.py
fi
request_pre_shutdown
wait_for_pre_shutdown_complete_or_fail
if [[ "x$sonic_asic_type" == x"mellanox" ]]; then
check_issu_bank_file
if [[ "${service}" = "nat" || "${service}" = "sflow" || "${service}" = "lldp" ]]; then
container kill "${service}" &> /dev/null || debug "Docker ${service} is not running ($?) ..."
fi
# Warm reboot: dump state to host disk
if [[ "$REBOOT_TYPE" = "fastfast-reboot" ]]; then
sonic-db-cli ASIC_DB FLUSHDB > /dev/null
sonic-db-cli COUNTERS_DB FLUSHDB > /dev/null
sonic-db-cli FLEX_COUNTER_DB FLUSHDB > /dev/null
if [[ "${service}" = "syncd" ]]; then
systemctl stop ${service} || debug "Ignore stopping ${service} service error $?"
else
systemctl stop ${service}
fi
# TODO: backup_database preserves FDB_TABLE
# need to cleanup as well for fastfast boot case
backup_database
debug "Stopped ${service}"
# Stop teamd gracefully
debug "Stopping teamd ..."
systemctl stop teamd
debug "Stopped teamd ..."
fi
if [[ "${service}" = "swss" ]]; then
if [[ "$REBOOT_TYPE" = "warm-reboot" || "$REBOOT_TYPE" = "fastfast-reboot" ]]; then
# Pre-shutdown syncd
initialize_pre_shutdown
if [[ "x$sonic_asic_type" == x"mellanox" ]]; then
check_issu_bank_file
fi
debug "Stopping syncd ..."
systemctl stop syncd || debug "Ignore stopping syncd service error $?"
debug "Stopped syncd ..."
request_pre_shutdown
wait_for_pre_shutdown_complete_or_fail
if [[ "x$sonic_asic_type" == x"mellanox" ]]; then
check_issu_bank_file
fi
# Warm reboot: dump state to host disk
if [[ "$REBOOT_TYPE" = "fastfast-reboot" ]]; then
sonic-db-cli ASIC_DB FLUSHDB > /dev/null
sonic-db-cli COUNTERS_DB FLUSHDB > /dev/null
sonic-db-cli FLEX_COUNTER_DB FLUSHDB > /dev/null
fi
# TODO: backup_database preserves FDB_TABLE
# need to cleanup as well for fastfast boot case
backup_database
fi
fi
done
# Kill other containers to make the reboot faster
# We call `docker kill ...` to ensure the container stops as quickly as possible,
Expand Down
15 changes: 15 additions & 0 deletions scripts/generate_shutdown_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/python3

''' This script is used to generate initial warm/fast shutdown order file '''

from sonic_package_manager import PackageManager

def main():
manager = PackageManager.get_manager()
installed_packages = manager.get_installed_packages()
print('installed packages {}'.format(installed_packages))
manager.service_creator.generate_shutdown_sequence_files(installed_packages)
print('Done.')

if __name__ == '__main__':
main()
8 changes: 5 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
'scripts/fdbshow',
'scripts/gearboxutil',
'scripts/generate_dump',
'scripts/generate_shutdown_order.py',
'scripts/intfutil',
'scripts/intfstat',
'scripts/ipintutil',
Expand Down Expand Up @@ -186,9 +187,10 @@
'sonic-py-common',
'sonic-yang-mgmt',
'swsssdk>=2.0.1',
'tabulate>=0.8.2',
'www-authenticate>=0.9.2',
'xmltodict>=0.12.0',
'tabulate==0.8.2',
'toposort==1.6',
'www-authenticate==0.9.2',
'xmltodict==0.12.0',
],
setup_requires= [
'pytest-runner',
Expand Down
38 changes: 33 additions & 5 deletions sonic_package_manager/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import pkgutil
import tempfile
from inspect import signature
from typing import Any, Iterable, Callable, Dict, Optional
from typing import Any, Iterable, List, Callable, Dict, Optional

import docker
import filelock
Expand Down Expand Up @@ -375,6 +375,14 @@ def install_from_source(self,
self.service_creator.create(package, state=feature_state, owner=default_owner)
exits.callback(rollback(self.service_creator.remove, package))

self.service_creator.generate_shutdown_sequence_files(
self._get_installed_packages_and(package)
)
exits.callback(rollback(
self.service_creator.generate_shutdown_sequence_files,
self.get_installed_packages())
)

if not skip_host_plugins:
self._install_cli_plugins(package)
exits.callback(rollback(self._uninstall_cli_plugins, package))
Expand Down Expand Up @@ -429,6 +437,9 @@ def uninstall(self, name: str, force=False):
try:
self._uninstall_cli_plugins(package)
self.service_creator.remove(package)
self.service_creator.generate_shutdown_sequence_files(
self._get_installed_packages_except(package)
)

# Clean containers based on this image
containers = self.docker.ps(filters={'ancestor': package.image_id},
Expand Down Expand Up @@ -525,8 +536,8 @@ def upgrade_from_source(self,
old_package, 'start'))

self.service_creator.remove(old_package, deregister_feature=False)
exits.callback(rollback(self.service_creator.create,
old_package, register_feature=False))
exits.callback(rollback(self.service_creator.create, old_package,
register_feature=False))

# Clean containers based on the old image
containers = self.docker.ps(filters={'ancestor': old_package.image_id},
Expand All @@ -538,6 +549,14 @@ def upgrade_from_source(self,
exits.callback(rollback(self.service_creator.remove, new_package,
register_feature=False))

self.service_creator.generate_shutdown_sequence_files(
self._get_installed_packages_and(new_package)
)
exits.callback(rollback(
self.service_creator.generate_shutdown_sequence_files,
self._get_installed_packages_and(old_package))
)

if self.feature_registry.is_feature_enabled(new_feature):
self._systemctl_action(new_package, 'start')
exits.callback(rollback(self._systemctl_action,
Expand Down Expand Up @@ -817,10 +836,19 @@ def get_installed_packages(self) -> Dict[str, Package]:
"""

return {
entry.name: self.get_installed_package(entry.name)
for entry in self.database if entry.installed
entry.name: entry for entry in self.get_installed_packages_list()
}

def get_installed_packages_list(self) -> List[Package]:
""" Returns a list of installed packages.

Returns:
Installed packages dictionary.
"""

return [self.get_installed_package(entry.name)
for entry in self.database if entry.installed]

def _migrate_package_database(self, old_package_database: PackageDatabase):
""" Performs part of package migration process.
For every package in old_package_database that is not listed in current
Expand Down
25 changes: 19 additions & 6 deletions sonic_package_manager/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,10 @@ class ManifestRoot(ManifestNode):

def marshal(self, value: Optional[dict]):
result = {}
if value is None:
value = {}
value = value or {}

if not isinstance(value, dict):
raise ManifestError(f'"{self.key}" field has to be a dictionary')

for item in self.items:
next_value = value.get(item.key)
Expand All @@ -115,7 +117,7 @@ def marshal(self, value):
if value is None:
if self.default is not None:
return self.default
raise ManifestError(f'{self.key} is a required field but it is missing')
raise ManifestError(f'"{self.key}" is a required field but it is missing')
try:
return_value = self.type.marshal(value)
except Exception as err:
Expand All @@ -130,10 +132,12 @@ class ManifestArray(ManifestNode):
type: Any

def marshal(self, value):
if value is None:
return []

return_value = []
value = value or []

if not isinstance(value, list):
raise ManifestError(f'"{self.key}" has to be of type list')

try:
for item in value:
return_value.append(self.type.marshal(item))
Expand Down Expand Up @@ -173,6 +177,14 @@ def unmarshal(self, value):
ManifestField('asic-service', DefaultMarshaller(bool), False),
ManifestField('host-service', DefaultMarshaller(bool), True),
ManifestField('delayed', DefaultMarshaller(bool), False),
ManifestRoot('warm-shutdown', [
ManifestArray('after', DefaultMarshaller(str)),
ManifestArray('before', DefaultMarshaller(str)),
]),
ManifestRoot('fast-shutdown', [
ManifestArray('after', DefaultMarshaller(str)),
ManifestArray('before', DefaultMarshaller(str)),
]),
]),
ManifestRoot('container', [
ManifestField('privileged', DefaultMarshaller(bool), False),
Expand All @@ -187,6 +199,7 @@ def unmarshal(self, value):
]),
ManifestArray('processes', ManifestRoot('processes', [
ManifestField('name', DefaultMarshaller(str)),
ManifestField('reconciles', DefaultMarshaller(bool), False),
])),
ManifestRoot('cli', [
ManifestField('mandatory', DefaultMarshaller(bool), False),
Expand Down
Loading