Skip to content

Commit 86eb51f

Browse files
committed
Add dbus support for below commands:
config apply-patch config checkpoint config delete checkpoint config reload
1 parent 2c0e6de commit 86eb51f

File tree

8 files changed

+393
-2
lines changed

8 files changed

+393
-2
lines changed

host_modules/config_engine.py

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
"""Config command handler"""
2+
3+
from host_modules import host_service
4+
import subprocess
5+
import os
6+
import shutil
7+
8+
MOD_NAME = 'config'
9+
DEFAULT_CONFIG = '/etc/sonic/config_db.json'
10+
11+
class Config(host_service.HostModule):
12+
"""
13+
DBus endpoint that executes the config command
14+
"""
15+
@host_service.method(host_service.bus_name(MOD_NAME), in_signature='s', out_signature='is')
16+
def reload(self, config_file):
17+
18+
cmd = ['/usr/local/bin/config', 'reload', '-y']
19+
if config_file and config_file != DEFAULT_CONFIG:
20+
if not os.path.exists(config_file):
21+
return -1, "Can't find %s"%config_file
22+
# Persistent Config
23+
shutil.move(config_file, DEFAULT_CONFIG)
24+
25+
result = subprocess.run(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
26+
msg = ''
27+
if result.returncode:
28+
lines = result.stderr.decode().split('\n')
29+
for line in lines[::-1]:
30+
if 'Error' in line:
31+
msg = line
32+
break
33+
return result.returncode, msg
34+
35+
@host_service.method(host_service.bus_name(MOD_NAME), in_signature='s', out_signature='is')
36+
def save(self, config_file):
37+
38+
cmd = ['/usr/local/bin/config', 'save', '-y']
39+
if config_file and config_file != DEFAULT_CONFIG:
40+
cmd.append(config_file)
41+
42+
result = subprocess.run(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
43+
msg = ''
44+
if result.returncode:
45+
lines = result.stderr.decode().split('\n')
46+
for line in lines[::-1]:
47+
if 'Error' in line:
48+
msg = line
49+
break
50+
return result.returncode, msg
51+
52+
def register():
53+
"""Return the class name"""
54+
return Config, MOD_NAME
55+

host_modules/gcu.py

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
"""Generic config updater command handler"""
2+
3+
from host_modules import host_service
4+
import subprocess
5+
6+
MOD_NAME = 'gcu'
7+
8+
class GCU(host_service.HostModule):
9+
"""
10+
DBus endpoint that executes the generic config updater command
11+
"""
12+
@host_service.method(host_service.bus_name(MOD_NAME), in_signature='s', out_signature='is')
13+
def apply_patch_db(self, patch_file_path):
14+
15+
cmd = ['/usr/local/bin/config', 'apply-patch', '-f', 'CONFIGDB', patch_file_path]
16+
17+
result = subprocess.run(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
18+
msg = ''
19+
if result.returncode:
20+
lines = result.stderr.decode().split('\n')
21+
for line in lines[::-1]:
22+
if 'Error' in line:
23+
msg = line
24+
break
25+
return result.returncode, msg
26+
27+
@host_service.method(host_service.bus_name(MOD_NAME), in_signature='s', out_signature='is')
28+
def apply_patch_yang(self, patch_file_path):
29+
30+
cmd = ['/usr/local/bin/config', 'apply-patch', '-f', 'SONICYANG', patch_file_path]
31+
32+
result = subprocess.run(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
33+
msg = ''
34+
if result.returncode:
35+
lines = result.stderr.decode().split('\n')
36+
for line in lines[::-1]:
37+
if 'Error' in line:
38+
msg = line
39+
break
40+
return result.returncode, msg
41+
42+
@host_service.method(host_service.bus_name(MOD_NAME), in_signature='s', out_signature='is')
43+
def create_checkpoint(self, checkpoint_file):
44+
45+
cmd = ['/usr/local/bin/config', 'checkpoint', checkpoint_file]
46+
47+
result = subprocess.run(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
48+
msg = ''
49+
if result.returncode:
50+
lines = result.stderr.decode().split('\n')
51+
for line in lines[::-1]:
52+
if 'Error' in line:
53+
msg = line
54+
break
55+
return result.returncode, msg
56+
57+
@host_service.method(host_service.bus_name(MOD_NAME), in_signature='s', out_signature='is')
58+
def delete_checkpoint(self, checkpoint_file):
59+
60+
cmd = ['/usr/local/bin/config', 'delete-checkpoint', checkpoint_file]
61+
62+
result = subprocess.run(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
63+
msg = ''
64+
if result.returncode:
65+
lines = result.stderr.decode().split('\n')
66+
for line in lines[::-1]:
67+
if 'Error' in line:
68+
msg = line
69+
break
70+
return result.returncode, msg
71+
72+
def register():
73+
"""Return the class name"""
74+
return GCU, MOD_NAME
75+

host_modules/showtech.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Show techsupport command handler"""
22

3-
import host_service
3+
from host_modules import host_service
44
import subprocess
55
import re
66

pytest.ini

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
[pytest]
2-
addopts = --cov=scripts --cov-report html --cov-report term --cov-report xml --ignore=tests/*/test*_vectors.py --junitxml=test-results.xml -vv
2+
addopts = --cov=scripts --cov=host_modules --cov-report html --cov-report term --cov-report xml --ignore=tests/*/test*_vectors.py --junitxml=test-results.xml -vv

tests/host_modules/__init__.py

Whitespace-only changes.

tests/host_modules/config_test.py

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import sys
2+
import os
3+
import pytest
4+
from unittest import mock
5+
from host_modules import config_engine
6+
7+
class TestConfigEngine(object):
8+
@mock.patch("dbus.SystemBus")
9+
@mock.patch("dbus.service.BusName")
10+
@mock.patch("dbus.service.Object.__init__")
11+
def test_reload(self, MockInit, MockBusName, MockSystemBus):
12+
with mock.patch("os.path.exists") as mock_exists, mock.patch("shutil.move") as mock_move:
13+
mock_exists.return_value=True
14+
with mock.patch("subprocess.run") as mock_run:
15+
res_mock = mock.Mock()
16+
test_ret = 0
17+
test_msg = b"Error: this is the test message\nHello world\n"
18+
attrs = {"returncode": test_ret, "stderr": test_msg}
19+
res_mock.configure_mock(**attrs)
20+
mock_run.return_value = res_mock
21+
config_file = "test.json"
22+
config_stub = config_engine.Config(config_engine.MOD_NAME)
23+
ret, msg = config_stub.reload(config_file)
24+
call_args = mock_run.call_args[0][0]
25+
assert "reload" in call_args
26+
assert config_file not in call_args
27+
assert ret == test_ret, "Return value is wrong"
28+
assert msg == "", "Return message is wrong"
29+
with mock.patch("subprocess.run") as mock_run:
30+
res_mock = mock.Mock()
31+
test_ret = 1
32+
test_msg = b"Error: this is the test message\nHello world\n"
33+
attrs = {"returncode": test_ret, "stderr": test_msg}
34+
res_mock.configure_mock(**attrs)
35+
mock_run.return_value = res_mock
36+
config_file = "test.json"
37+
config_stub = config_engine.Config(config_engine.MOD_NAME)
38+
ret, msg = config_stub.reload(config_file)
39+
call_args = mock_run.call_args[0][0]
40+
assert "reload" in call_args
41+
assert config_file not in call_args
42+
assert ret == test_ret, "Return value is wrong"
43+
assert msg == "Error: this is the test message", "Return message is wrong"
44+
45+
@mock.patch("dbus.SystemBus")
46+
@mock.patch("dbus.service.BusName")
47+
@mock.patch("dbus.service.Object.__init__")
48+
def test_save(self, MockInit, MockBusName, MockSystemBus):
49+
with mock.patch("subprocess.run") as mock_run:
50+
res_mock = mock.Mock()
51+
test_ret = 0
52+
test_msg = b"Error: this is the test message\nHello world\n"
53+
attrs = {"returncode": test_ret, "stderr": test_msg}
54+
res_mock.configure_mock(**attrs)
55+
mock_run.return_value = res_mock
56+
config_file = "test.patch"
57+
config_stub = config_engine.Config(config_engine.MOD_NAME)
58+
ret, msg = config_stub.save(config_file)
59+
call_args = mock_run.call_args[0][0]
60+
assert "save" in call_args
61+
assert config_file in call_args
62+
assert ret == test_ret, "Return value is wrong"
63+
assert msg == "", "Return message is wrong"
64+
with mock.patch("subprocess.run") as mock_run:
65+
res_mock = mock.Mock()
66+
test_ret = 1
67+
test_msg = b"Error: this is the test message\nHello world\n"
68+
attrs = {"returncode": test_ret, "stderr": test_msg}
69+
res_mock.configure_mock(**attrs)
70+
mock_run.return_value = res_mock
71+
config_file = "test.patch"
72+
config_stub = config_engine.Config(config_engine.MOD_NAME)
73+
ret, msg = config_stub.save(config_file)
74+
call_args = mock_run.call_args[0][0]
75+
assert "save" in call_args
76+
assert config_file in call_args
77+
assert ret == test_ret, "Return value is wrong"
78+
assert msg == "Error: this is the test message", "Return message is wrong"
79+

tests/host_modules/gcu_test.py

+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import sys
2+
import os
3+
import pytest
4+
from unittest import mock
5+
from host_modules import gcu
6+
7+
class TestGCU(object):
8+
@mock.patch("dbus.SystemBus")
9+
@mock.patch("dbus.service.BusName")
10+
@mock.patch("dbus.service.Object.__init__")
11+
def test_apply_patch_db(self, MockInit, MockBusName, MockSystemBus):
12+
with mock.patch("subprocess.run") as mock_run:
13+
res_mock = mock.Mock()
14+
test_ret = 0
15+
test_msg = b"Error: this is the test message\nHello world\n"
16+
attrs = {"returncode": test_ret, "stderr": test_msg}
17+
res_mock.configure_mock(**attrs)
18+
mock_run.return_value = res_mock
19+
patch_file = "test.patch"
20+
gcu_stub = gcu.GCU(gcu.MOD_NAME)
21+
ret, msg = gcu_stub.apply_patch_db(patch_file)
22+
call_args = mock_run.call_args[0][0]
23+
assert "apply-patch" in call_args
24+
assert "CONFIGDB" in call_args
25+
assert patch_file in call_args
26+
assert ret == test_ret, "Return value is wrong"
27+
assert msg == "", "Return message is wrong"
28+
with mock.patch("subprocess.run") as mock_run:
29+
res_mock = mock.Mock()
30+
test_ret = 1
31+
test_msg = b"Error: this is the test message\nHello world\n"
32+
attrs = {"returncode": test_ret, "stderr": test_msg}
33+
res_mock.configure_mock(**attrs)
34+
mock_run.return_value = res_mock
35+
patch_file = "test.patch"
36+
gcu_stub = gcu.GCU(gcu.MOD_NAME)
37+
ret, msg = gcu_stub.apply_patch_db(patch_file)
38+
call_args = mock_run.call_args[0][0]
39+
assert "apply-patch" in call_args
40+
assert "CONFIGDB" in call_args
41+
assert patch_file in call_args
42+
assert ret == test_ret, "Return value is wrong"
43+
assert msg == "Error: this is the test message", "Return message is wrong"
44+
45+
@mock.patch("dbus.SystemBus")
46+
@mock.patch("dbus.service.BusName")
47+
@mock.patch("dbus.service.Object.__init__")
48+
def test_apply_patch_yang(self, MockInit, MockBusName, MockSystemBus):
49+
with mock.patch("subprocess.run") as mock_run:
50+
res_mock = mock.Mock()
51+
test_ret = 0
52+
test_msg = b"Error: this is the test message\nHello world\n"
53+
attrs = {"returncode": test_ret, "stderr": test_msg}
54+
res_mock.configure_mock(**attrs)
55+
mock_run.return_value = res_mock
56+
patch_file = "test.patch"
57+
gcu_stub = gcu.GCU(gcu.MOD_NAME)
58+
ret, msg = gcu_stub.apply_patch_yang(patch_file)
59+
call_args = mock_run.call_args[0][0]
60+
assert "apply-patch" in call_args
61+
assert "SONICYANG" in call_args
62+
assert patch_file in call_args
63+
assert ret == test_ret, "Return value is wrong"
64+
assert msg == "", "Return message is wrong"
65+
with mock.patch("subprocess.run") as mock_run:
66+
res_mock = mock.Mock()
67+
test_ret = 1
68+
test_msg = b"Error: this is the test message\nHello world\n"
69+
attrs = {"returncode": test_ret, "stderr": test_msg}
70+
res_mock.configure_mock(**attrs)
71+
mock_run.return_value = res_mock
72+
patch_file = "test.patch"
73+
gcu_stub = gcu.GCU(gcu.MOD_NAME)
74+
ret, msg = gcu_stub.apply_patch_yang(patch_file)
75+
call_args = mock_run.call_args[0][0]
76+
assert "apply-patch" in call_args
77+
assert "SONICYANG" in call_args
78+
assert patch_file in call_args
79+
assert ret == test_ret, "Return value is wrong"
80+
assert msg == "Error: this is the test message", "Return message is wrong"
81+
82+
@mock.patch("dbus.SystemBus")
83+
@mock.patch("dbus.service.BusName")
84+
@mock.patch("dbus.service.Object.__init__")
85+
def test_create_checkpoint(self, MockInit, MockBusName, MockSystemBus):
86+
with mock.patch("subprocess.run") as mock_run:
87+
res_mock = mock.Mock()
88+
test_ret = 0
89+
test_msg = b"Error: this is the test message\nHello world\n"
90+
attrs = {"returncode": test_ret, "stderr": test_msg}
91+
res_mock.configure_mock(**attrs)
92+
mock_run.return_value = res_mock
93+
cp_name = "test_name"
94+
gcu_stub = gcu.GCU(gcu.MOD_NAME)
95+
ret, msg = gcu_stub.create_checkpoint(cp_name)
96+
call_args = mock_run.call_args[0][0]
97+
assert "checkpoint" in call_args
98+
assert "delete-checkpoint" not in call_args
99+
assert cp_name in call_args
100+
assert ret == test_ret, "Return value is wrong"
101+
assert msg == "", "Return message is wrong"
102+
with mock.patch("subprocess.run") as mock_run:
103+
res_mock = mock.Mock()
104+
test_ret = 1
105+
test_msg = b"Error: this is the test message\nHello world\n"
106+
attrs = {"returncode": test_ret, "stderr": test_msg}
107+
res_mock.configure_mock(**attrs)
108+
mock_run.return_value = res_mock
109+
cp_name = "test_name"
110+
gcu_stub = gcu.GCU(gcu.MOD_NAME)
111+
ret, msg = gcu_stub.create_checkpoint(cp_name)
112+
call_args = mock_run.call_args[0][0]
113+
assert "checkpoint" in call_args
114+
assert "delete-checkpoint" not in call_args
115+
assert cp_name in call_args
116+
assert ret == test_ret, "Return value is wrong"
117+
assert msg == "Error: this is the test message", "Return message is wrong"
118+
119+
@mock.patch("dbus.SystemBus")
120+
@mock.patch("dbus.service.BusName")
121+
@mock.patch("dbus.service.Object.__init__")
122+
def test_delete_checkpoint(self, MockInit, MockBusName, MockSystemBus):
123+
with mock.patch("subprocess.run") as mock_run:
124+
res_mock = mock.Mock()
125+
test_ret = 0
126+
test_msg = b"Error: this is the test message\nHello world\n"
127+
attrs = {"returncode": test_ret, "stderr": test_msg}
128+
res_mock.configure_mock(**attrs)
129+
mock_run.return_value = res_mock
130+
cp_name = "test_name"
131+
gcu_stub = gcu.GCU(gcu.MOD_NAME)
132+
ret, msg = gcu_stub.delete_checkpoint(cp_name)
133+
call_args = mock_run.call_args[0][0]
134+
assert "delete-checkpoint" in call_args
135+
assert cp_name in call_args
136+
assert ret == test_ret, "Return value is wrong"
137+
assert msg == "", "Return message is wrong"
138+
with mock.patch("subprocess.run") as mock_run:
139+
res_mock = mock.Mock()
140+
test_ret = 1
141+
test_msg = b"Error: this is the test message\nHello world\n"
142+
attrs = {"returncode": test_ret, "stderr": test_msg}
143+
res_mock.configure_mock(**attrs)
144+
mock_run.return_value = res_mock
145+
cp_name = "test_name"
146+
gcu_stub = gcu.GCU(gcu.MOD_NAME)
147+
ret, msg = gcu_stub.delete_checkpoint(cp_name)
148+
call_args = mock_run.call_args[0][0]
149+
assert "delete-checkpoint" in call_args
150+
assert cp_name in call_args
151+
assert ret == test_ret, "Return value is wrong"
152+
assert msg == "Error: this is the test message", "Return message is wrong"
153+

0 commit comments

Comments
 (0)