Skip to content

Commit f609301

Browse files
committed
show commands for system ready and application extension package app ready support
1 parent 9e2fbf4 commit f609301

File tree

8 files changed

+223
-1
lines changed

8 files changed

+223
-1
lines changed

scripts/sysreadyshow

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
#!/usr/bin/env python3
2+
3+
"""
4+
Script to show system ready status.
5+
"""
6+
7+
import os
8+
import sys
9+
import argparse
10+
from tabulate import tabulate
11+
from natsort import natsorted
12+
13+
# mock the redis for unit test purposes #
14+
try:
15+
if os.environ["UTILITIES_UNIT_TESTING"] == "1":
16+
modules_path = os.path.join(os.path.dirname(__file__), "..")
17+
test_path = os.path.join(modules_path, "tests")
18+
sys.path.insert(0, modules_path)
19+
sys.path.insert(0, test_path)
20+
import mock_tables.dbconnector
21+
except KeyError:
22+
pass
23+
24+
from swsscommon.swsscommon import SonicV2Connector
25+
26+
header = ['Service-Name', 'Service-Status', 'App-Ready-Status', 'Down-Reason']
27+
header_detail = ['Service-Name', 'Service-Status', 'App-Ready-Status', 'Down-Reason', 'AppStatus-UpdateTime']
28+
29+
ALL_TABLE_NAME = 'ALL_SERVICE_STATUS'
30+
SERVICE_STATUS = 'service_status'
31+
APP_READY_STATUS = 'app_ready_status'
32+
FAIL_REASON = 'fail_reason'
33+
UPDATE_TIME = 'update_time'
34+
35+
class SysreadyShow(object):
36+
def __init__(self):
37+
self.db = SonicV2Connector(host="127.0.0.1")
38+
self.db.connect(self.db.STATE_DB)
39+
40+
def show(self,type):
41+
TABLE_NAME = ALL_TABLE_NAME
42+
SYSREADY_TABLE = "SYSTEM_READY|SYSTEM_STATE"
43+
44+
keys = self.db.keys(self.db.STATE_DB, TABLE_NAME + '*')
45+
if not keys:
46+
print('No info\n')
47+
return
48+
49+
table = []
50+
for key in natsorted(keys):
51+
key_list = key.split('|')
52+
if len(key_list) != 2: # error data in DB, log it and ignore
53+
print('Warn: Invalid key in table {}: {}'.format(TABLE_NAME, key))
54+
continue
55+
56+
name = key_list[1]
57+
data_dict = self.db.get_all(self.db.STATE_DB, key)
58+
try:
59+
service_status = data_dict[SERVICE_STATUS]
60+
app_ready_status = data_dict[APP_READY_STATUS]
61+
fail_reason = data_dict[FAIL_REASON]
62+
update_time = data_dict[UPDATE_TIME]
63+
except ValueError as e:
64+
print('Error in data_dict')
65+
66+
if type == "alldetail":
67+
table.append((name, service_status, app_ready_status, fail_reason, update_time))
68+
header_info = header_detail
69+
else:
70+
table.append((name, service_status, app_ready_status, fail_reason))
71+
header_info = header
72+
73+
sysready_state = self.db.get(self.db.STATE_DB, SYSREADY_TABLE, "Status")
74+
if sysready_state == "UP":
75+
print("System is ready\n")
76+
else:
77+
print("System is not ready - one or more services are not up\n")
78+
79+
80+
if type == "allbrief":
81+
return
82+
83+
84+
if table:
85+
print(tabulate(table, header_info, tablefmt='simple', stralign='left'))
86+
else:
87+
print('No sysready status data available\n')
88+
89+
90+
def main():
91+
parser = argparse.ArgumentParser(description='Display the System Ready status',
92+
formatter_class=argparse.RawTextHelpFormatter,
93+
epilog="""
94+
Examples:
95+
sysreadyshow --all
96+
sysreadyshow --allbrief
97+
sysreadyshow --alldetail
98+
""")
99+
100+
parser.add_argument('-a', '--all', action='store_true', help='all service status', default=True)
101+
parser.add_argument('-b', '--allbrief', action='store_true', help='all service status brief', default=False)
102+
parser.add_argument('-d', '--alldetail', action='store_true', help='all service status detail', default=False)
103+
args = parser.parse_args()
104+
105+
try:
106+
sysready = SysreadyShow()
107+
if args.alldetail:
108+
sysready.show("alldetail")
109+
elif args.allbrief:
110+
sysready.show("allbrief")
111+
else:
112+
sysready.show("all")
113+
except Exception as e:
114+
print(str(e), file=sys.stderr)
115+
sys.exit(1)
116+
117+
118+
if __name__ == "__main__":
119+
main()

setup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@
146146
'scripts/null_route_helper',
147147
'scripts/coredump_gen_handler.py',
148148
'scripts/techsupport_cleanup.py',
149-
'scripts/check_db_integrity.py'
149+
'scripts/check_db_integrity.py',
150+
'scripts/sysreadyshow'
150151
],
151152
entry_points={
152153
'console_scripts': [

show/system_health.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,3 +198,34 @@ def monitor_list():
198198
entry.append(element[1]['type'])
199199
table.append(entry)
200200
click.echo(tabulate(table, header))
201+
202+
203+
@system_health.group('sysready-status',invoke_without_command=True)
204+
@click.pass_context
205+
def sysready_status(ctx):
206+
"""Show system-health system ready status"""
207+
208+
if ctx.invoked_subcommand is None:
209+
try:
210+
cmd = "sysreadyshow --all"
211+
clicommon.run_command(cmd, display_cmd=False)
212+
except Exception as e:
213+
click.echo("Exception: {}".format(str(e)))
214+
215+
216+
@sysready_status.command('brief')
217+
def sysready_status_brief():
218+
try:
219+
cmd = "sysreadyshow --allbrief"
220+
clicommon.run_command(cmd, display_cmd=False)
221+
except Exception as e:
222+
click.echo("Exception: {}".format(str(e)))
223+
224+
225+
@sysready_status.command('detail')
226+
def sysready_status_detail():
227+
try:
228+
cmd = "sysreadyshow --alldetail"
229+
clicommon.run_command(cmd, display_cmd=False)
230+
except Exception as e:
231+
click.echo("Exception: {}".format(str(e)))

sonic_package_manager/manifest.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ def unmarshal(self, value):
177177
ManifestField('asic-service', DefaultMarshaller(bool), False),
178178
ManifestField('host-service', DefaultMarshaller(bool), True),
179179
ManifestField('delayed', DefaultMarshaller(bool), False),
180+
ManifestField('check_up_status', DefaultMarshaller(bool), False),
180181
ManifestRoot('warm-shutdown', [
181182
ManifestArray('after', DefaultMarshaller(str)),
182183
ManifestArray('before', DefaultMarshaller(str)),

sonic_package_manager/service_creator/feature.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,4 +143,5 @@ def get_non_configurable_feature_entries(manifest) -> Dict[str, str]:
143143
'has_per_asic_scope': str(manifest['service']['asic-service']),
144144
'has_global_scope': str(manifest['service']['host-service']),
145145
'has_timer': str(manifest['service']['delayed']),
146+
'check_up_status': str(manifest['service']['check_up_status']),
146147
}

tests/mock_tables/state_db.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,5 +726,32 @@
726726
"pck_expected_count": "840",
727727
"link_prober_unknown_start": "2022-Jan-26 03:13:05.366900",
728728
"link_prober_unknown_end": "2022-Jan-26 03:17:35.446580"
729+
},
730+
"ALL_SERVICE_STATUS|mgmt-framework": {
731+
"app_ready_status": "OK",
732+
"fail_reason": "-",
733+
"service_status": "OK",
734+
"update_time": "-"
735+
},
736+
"ALL_SERVICE_STATUS|swss": {
737+
"app_ready_status": "OK",
738+
"fail_reason": "-",
739+
"service_status": "OK",
740+
"update_time": "-"
741+
},
742+
"ALL_SERVICE_STATUS|bgp": {
743+
"app_ready_status": "Down",
744+
"fail_reason": "Inactive",
745+
"service_status": "Down",
746+
"update_time": "-"
747+
},
748+
"ALL_SERVICE_STATUS|pmon": {
749+
"app_ready_status": "OK",
750+
"fail_reason": "-",
751+
"service_status": "OK",
752+
"update_time": "-"
753+
},
754+
"SYSTEM_READY|SYSTEM_STATE": {
755+
"Status":"DOWN"
729756
}
730757
}

tests/sonic_package_manager/test_service_creator.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ def test_feature_registration(mock_sonic_db, manifest):
215215
'has_per_asic_scope': 'False',
216216
'has_global_scope': 'True',
217217
'has_timer': 'False',
218+
'check_up_status': 'False',
218219
})
219220

220221

@@ -227,6 +228,7 @@ def test_feature_update(mock_sonic_db, manifest):
227228
'has_per_asic_scope': 'False',
228229
'has_global_scope': 'True',
229230
'has_timer': 'False',
231+
'check_up_status': 'False',
230232
}
231233
mock_connector = Mock()
232234
mock_connector.get_entry = Mock(return_value=curr_feature_config)
@@ -249,6 +251,7 @@ def test_feature_update(mock_sonic_db, manifest):
249251
'has_per_asic_scope': 'False',
250252
'has_global_scope': 'True',
251253
'has_timer': 'True',
254+
'check_up_status': 'False',
252255
}),
253256
], any_order=True)
254257

@@ -268,6 +271,7 @@ def test_feature_registration_with_timer(mock_sonic_db, manifest):
268271
'has_per_asic_scope': 'False',
269272
'has_global_scope': 'True',
270273
'has_timer': 'True',
274+
'check_up_status': 'False',
271275
})
272276

273277

@@ -285,4 +289,5 @@ def test_feature_registration_with_non_default_owner(mock_sonic_db, manifest):
285289
'has_per_asic_scope': 'False',
286290
'has_global_scope': 'True',
287291
'has_timer': 'False',
292+
'check_up_status': 'False',
288293
})

tests/system_health_test.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,43 @@ def test_health_detail(self):
306306
"""
307307
assert result.output == expected
308308

309+
def test_health_systemready(self):
310+
runner = CliRunner()
311+
result = runner.invoke(show.cli.commands["system-health"].commands["sysready-status"])
312+
click.echo(result.output)
313+
print("myresult:{}".format(result.output))
314+
expected = """\
315+
System is not ready - one or more services are not up
316+
317+
Service-Name Service-Status App-Ready-Status Down-Reason
318+
-------------- ---------------- ------------------ -------------
319+
bgp Down Down Inactive
320+
mgmt-framework OK OK -
321+
pmon OK OK -
322+
swss OK OK -
323+
"""
324+
assert result.output == expected
325+
result = runner.invoke(show.cli.commands["system-health"].commands["sysready-status"],["brief"])
326+
click.echo(result.output)
327+
print("myresult:{}".format(result.output))
328+
expected = """\
329+
System is not ready - one or more services are not up
330+
"""
331+
assert result.output == expected
332+
result = runner.invoke(show.cli.commands["system-health"].commands["sysready-status"],["detail"])
333+
click.echo(result.output)
334+
print("myresult:{}".format(result.output))
335+
expected = """\
336+
System is not ready - one or more services are not up
337+
338+
Service-Name Service-Status App-Ready-Status Down-Reason AppStatus-UpdateTime
339+
-------------- ---------------- ------------------ ------------- ----------------------
340+
bgp Down Down Inactive -
341+
mgmt-framework OK OK - -
342+
pmon OK OK - -
343+
swss OK OK - -
344+
"""
345+
309346
@classmethod
310347
def teardown_class(cls):
311348
print("TEARDOWN")

0 commit comments

Comments
 (0)