Skip to content

Commit 804e053

Browse files
stepanblyschakmssonicbld
authored andcommitted
[sonic-package-manager] remove leftovers from featured on uninstall (#3305)
- What I did Added code to remove leftover symlinks and directories created by featured. Featured creates a symlink to /dev/null when unit is masked and an auto restart configuration is left under corresponding service.d/ directory. - How I did it Added necessary changes and UT to cover it. - How to verify it Uninstall an extension and verify no leftovers from featured. Signed-off-by: Stepan Blyschak <[email protected]>
1 parent 673da6b commit 804e053

File tree

3 files changed

+55
-11
lines changed

3 files changed

+55
-11
lines changed

sonic_package_manager/service_creator/creator.py

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import contextlib
44
import os
5+
import glob
56
import sys
67
import shutil
78
import stat
@@ -33,6 +34,7 @@
3334
TIMER_UNIT_TEMPLATE = 'timer.unit.j2'
3435

3536
SYSTEMD_LOCATION = '/usr/lib/systemd/system'
37+
ETC_SYSTEMD_LOCATION = '/etc/systemd/system'
3638

3739
GENERATED_SERVICES_CONF_FILE = '/etc/sonic/generated_services.conf'
3840

@@ -92,18 +94,30 @@ def set_executable_bit(filepath):
9294
os.chmod(filepath, st.st_mode | stat.S_IEXEC)
9395

9496

95-
def remove_if_exists(path):
97+
def remove_file(path):
9698
""" Remove filepath if it exists """
9799

98-
if not os.path.exists(path):
99-
return
100+
try:
101+
os.remove(path)
102+
log.info(f'removed {path}')
103+
except FileNotFoundError:
104+
pass
105+
106+
107+
def remove_dir(path):
108+
""" Remove filepath if it exists """
109+
110+
try:
111+
shutil.rmtree(path)
112+
log.info(f'removed {path}')
113+
except FileNotFoundError:
114+
pass
100115

101-
os.remove(path)
102-
log.info(f'removed {path}')
103116

104117
def is_list_of_strings(command):
105118
return isinstance(command, list) and all(isinstance(item, str) for item in command)
106119

120+
107121
def run_command(command: List[str]):
108122
""" Run arbitrary bash command.
109123
Args:
@@ -197,12 +211,22 @@ def remove(self,
197211
"""
198212

199213
name = package.manifest['service']['name']
200-
remove_if_exists(os.path.join(SYSTEMD_LOCATION, f'{name}.service'))
201-
remove_if_exists(os.path.join(SYSTEMD_LOCATION, f'{name}@.service'))
202-
remove_if_exists(os.path.join(SERVICE_MGMT_SCRIPT_LOCATION, f'{name}.sh'))
203-
remove_if_exists(os.path.join(DOCKER_CTL_SCRIPT_LOCATION, f'{name}.sh'))
204-
remove_if_exists(os.path.join(DEBUG_DUMP_SCRIPT_LOCATION, f'{name}'))
205-
remove_if_exists(os.path.join(ETC_SONIC_PATH, f'{name}_reconcile'))
214+
remove_file(os.path.join(SYSTEMD_LOCATION, f'{name}.service'))
215+
remove_file(os.path.join(SYSTEMD_LOCATION, f'{name}@.service'))
216+
remove_file(os.path.join(SERVICE_MGMT_SCRIPT_LOCATION, f'{name}.sh'))
217+
remove_file(os.path.join(DOCKER_CTL_SCRIPT_LOCATION, f'{name}.sh'))
218+
remove_file(os.path.join(DEBUG_DUMP_SCRIPT_LOCATION, f'{name}'))
219+
remove_file(os.path.join(ETC_SONIC_PATH, f'{name}_reconcile'))
220+
221+
# remove symlinks and configuration directories created by featured
222+
remove_file(os.path.join(ETC_SYSTEMD_LOCATION, f'{name}.service'))
223+
for unit_file in glob.glob(os.path.join(ETC_SYSTEMD_LOCATION, f'{name}@*.service')):
224+
remove_file(unit_file)
225+
226+
remove_dir(os.path.join(ETC_SYSTEMD_LOCATION, f'{name}.service.d'))
227+
for unit_dir in glob.glob(os.path.join(ETC_SYSTEMD_LOCATION, f'{name}@*.service.d')):
228+
remove_dir(unit_dir)
229+
206230
self.update_dependent_list_file(package, remove=True)
207231
self.update_generated_services_conf_file(package, remove=True)
208232

tests/sonic_package_manager/conftest.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from sonic_package_manager.registry import RegistryResolver
1717
from sonic_package_manager.version import Version
1818
from sonic_package_manager.service_creator.creator import *
19+
from sonic_package_manager.service_creator.creator import ETC_SYSTEMD_LOCATION
1920

2021

2122
@pytest.fixture
@@ -405,6 +406,7 @@ def fake_db_for_migration(fake_metadata_resolver):
405406
def sonic_fs(fs):
406407
fs.create_file('/proc/1/root')
407408
fs.create_dir(ETC_SONIC_PATH)
409+
fs.create_dir(ETC_SYSTEMD_LOCATION)
408410
fs.create_dir(SYSTEMD_LOCATION)
409411
fs.create_dir(DOCKER_CTL_SCRIPT_LOCATION)
410412
fs.create_dir(SERVICE_MGMT_SCRIPT_LOCATION)

tests/sonic_package_manager/test_service_creator.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from sonic_package_manager.metadata import Metadata
1313
from sonic_package_manager.package import Package
1414
from sonic_package_manager.service_creator.creator import *
15+
from sonic_package_manager.service_creator.creator import ETC_SYSTEMD_LOCATION
1516
from sonic_package_manager.service_creator.feature import FeatureRegistry
1617

1718

@@ -106,6 +107,14 @@ def test_service_creator(sonic_fs, manifest, service_creator, package_manager):
106107
assert sonic_fs.exists(os.path.join(SERVICE_MGMT_SCRIPT_LOCATION, 'test.sh'))
107108
assert sonic_fs.exists(os.path.join(SYSTEMD_LOCATION, 'test.service'))
108109

110+
# Create symlinks and directory featured creates
111+
os.symlink('/dev/null', os.path.join(ETC_SYSTEMD_LOCATION, 'test.service'))
112+
os.symlink('/dev/null', os.path.join(ETC_SYSTEMD_LOCATION, '[email protected]'))
113+
os.symlink('/dev/null', os.path.join(ETC_SYSTEMD_LOCATION, '[email protected]'))
114+
os.mkdir(os.path.join(ETC_SYSTEMD_LOCATION, 'test.service.d'))
115+
os.mkdir(os.path.join(ETC_SYSTEMD_LOCATION, '[email protected]'))
116+
os.mkdir(os.path.join(ETC_SYSTEMD_LOCATION, '[email protected]'))
117+
109118
def read_file(name):
110119
with open(os.path.join(ETC_SONIC_PATH, name)) as file:
111120
return file.read()
@@ -118,6 +127,15 @@ def read_file(name):
118127
assert generated_services_conf_content.endswith('\n')
119128
assert set(generated_services_conf_content.split()) == set(['test.service', '[email protected]'])
120129

130+
service_creator.remove(package)
131+
132+
assert not sonic_fs.exists(os.path.join(ETC_SYSTEMD_LOCATION, 'test.service'))
133+
assert not sonic_fs.exists(os.path.join(ETC_SYSTEMD_LOCATION, '[email protected]'))
134+
assert not sonic_fs.exists(os.path.join(ETC_SYSTEMD_LOCATION, '[email protected]'))
135+
assert not sonic_fs.exists(os.path.join(ETC_SYSTEMD_LOCATION, 'test.service.d'))
136+
assert not sonic_fs.exists(os.path.join(ETC_SYSTEMD_LOCATION, '[email protected]'))
137+
assert not sonic_fs.exists(os.path.join(ETC_SYSTEMD_LOCATION, '[email protected]'))
138+
121139

122140
def test_service_creator_with_timer_unit(sonic_fs, manifest, service_creator):
123141
entry = PackageEntry('test', 'azure/sonic-test')

0 commit comments

Comments
 (0)