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

Fix the issue when persistent DVS is used to run pytest which has number of front-panel ports < 32 #1373

Merged
merged 8 commits into from
Aug 18, 2020
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
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
6 changes: 6 additions & 0 deletions tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ For those developing new features for SWSS or the DVS framework, you might find
```
sudo pytest --dvsname=vs
```
By default if number of ports in persistent DVS < 32 (needed by testbed) then test will be aborted. To overcome that --forcedvs option can be used.

```
sudo pytest --dvsname=vs --forcedvs
```


5. Additionally, if you need to simulate a specific hardware platform (e.g. Broadcom or Mellanox), you can add this environment variable when starting the DVS container:

Expand Down
54 changes: 50 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ def ensure_system(cmd):
def pytest_addoption(parser):
parser.addoption("--dvsname", action="store", default=None,
help="dvs name")

parser.addoption("--forcedvs", action="store_true", default=False,
help="force persistent dvs when ports < 32 ")

abdosi marked this conversation as resolved.
Show resolved Hide resolved
parser.addoption("--keeptb", action="store_true", default=False,
help="keep testbed after test")
parser.addoption("--imgname", action="store", default="docker-sonic-vs",
Expand Down Expand Up @@ -170,7 +174,8 @@ def __init__(
keeptb=False,
fakeplatform=None,
log_path=None,
max_cpu=2
max_cpu=2,
forcedvs=None,
):
self.basicd = ['redis-server',
'rsyslogd']
Expand Down Expand Up @@ -199,6 +204,7 @@ def __init__(
self.cleanup = False
else:
self.cleanup = True
self.persistent = False
if name != None:
# get virtual switch container
for ctn in self.client.containers.list():
Expand All @@ -209,10 +215,20 @@ def __init__(
else:
(status, output) = subprocess.getstatusoutput("docker inspect --format '{{.HostConfig.NetworkMode}}' %s" % name)
ctn_sw_id = output.split(':')[1]
# Persistent DVS is available.
self.cleanup = False
self.persistent = True
if self.ctn == None:
raise NameError("cannot find container %s" % name)

self.num_net_interfaces = self.net_interface_count()

if self.num_net_interfaces > NUM_PORTS:
raise ValueError("persistent dvs is not valid for testbed with ports > %d" % NUM_PORTS)

if self.num_net_interfaces < NUM_PORTS and not forcedvs:
raise ValueError("persistent dvs does not have %d ports needed by testbed" % NUM_PORTS)

# get base container
for ctn in self.client.containers.list():
if ctn.id == ctn_sw_id or ctn.name == ctn_sw_id:
Expand All @@ -233,6 +249,10 @@ def __init__(
self.mount = "/var/run/redis-vs/{}".format(ctn_sw_name)

self.net_cleanup()
# As part of https://github.com/Azure/sonic-buildimage/pull/4499
# VS support dynamically create Front-panel ports so save the orginal
# config db for persistent DVS
self.runcmd("mv /etc/sonic/config_db.json /etc/sonic/config_db.json.orig")
self.ctn_restart()
else:
self.ctn_sw = self.client.containers.run('debian:jessie', privileged=True, detach=True,
Expand Down Expand Up @@ -280,7 +300,13 @@ def __init__(
def destroy(self):
if self.appldb:
del self.appldb
if self.cleanup:
# In case persistent dvs was used removed all the extra server link
# that were created
if self.persistent:
for s in self.servers:
s.destroy()
daall marked this conversation as resolved.
Show resolved Hide resolved
# persistent and clean-up flag are mutually exclusive
elif self.cleanup:
self.ctn.remove(force=True)
self.ctn_sw.remove(force=True)
os.system("rm -rf {}".format(self.mount))
Expand Down Expand Up @@ -397,6 +423,21 @@ def net_cleanup(self):
print("remove extra link {}".format(pname))
return

def net_interface_count(self):
"""get the interface count in persistent DVS Container
if not found or some error then return 0 as default"""

res = self.ctn.exec_run(['sh', '-c', 'ip link show | grep -oE eth[0-9]+ | grep -vc eth0'])
if not res.exit_code:
try:
out = res.output.decode('utf-8')
except AttributeError:
return 0
return int(out.rstrip('\n'))
else:
return 0


def ctn_restart(self):
self.ctn.restart()

Expand Down Expand Up @@ -885,7 +926,7 @@ def remove_neighbor(self, interface, ip):
def add_route(self, prefix, nexthop):
self.runcmd("ip route add " + prefix + " via " + nexthop)
time.sleep(1)

def remove_route(self, prefix):
self.runcmd("ip route del " + prefix)
time.sleep(1)
Expand Down Expand Up @@ -987,18 +1028,23 @@ def get_state_db(self):
@pytest.yield_fixture(scope="module")
def dvs(request) -> DockerVirtualSwitch:
name = request.config.getoption("--dvsname")
forcedvs = request.config.getoption("--forcedvs")
keeptb = request.config.getoption("--keeptb")
imgname = request.config.getoption("--imgname")
max_cpu = request.config.getoption("--max_cpu")
fakeplatform = getattr(request.module, "DVS_FAKE_PLATFORM", None)
log_path = name if name else request.module.__name__

dvs = DockerVirtualSwitch(name, imgname, keeptb, fakeplatform, log_path, max_cpu)
dvs = DockerVirtualSwitch(name, imgname, keeptb, fakeplatform, log_path, max_cpu, forcedvs)

yield dvs

dvs.get_logs()
dvs.destroy()
# restore original config db
if dvs.persistent:
dvs.runcmd("mv /etc/sonic/config_db.json.orig /etc/sonic/config_db.json")
dvs.ctn_restart()

@pytest.yield_fixture
def testlog(request, dvs):
Expand Down