-
Notifications
You must be signed in to change notification settings - Fork 851
[L1 Switch] Introduction of the L1 Switch API #8431
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
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most likely, configuring L1 switch is required in both ansible playbook and in pytest script. One possible better solution is to create some customized ansible modules and put them under ansible/library
.
Then in ansible playbook, we can call the modules to configure L1 switch or get status from L1 switch. In pytest, similarly, we can define a class like L1SwitchHost as a subclass of AnsibleHost and encapsulate some operations to call the customized modules as methods of this class.
Another possible direction is to use the netmiko
package installed in sonic-mgmt docker container. This package already has code for running random commands on remote host through SSH.
""" | ||
@summary: Class for L1 Switch | ||
|
||
For running commands on the L1 switch via ansible. Each port on the L1 switch consists of two uni-directional ports, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per my understanding, this class is to run commands through SSH connection established by paramiko, not through ansible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes that's right
|
||
def __init__(self, hostname, user, passwd, device_type="W2W ROME"): | ||
self.hostname = hostname | ||
self.type = device_type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better to use self.device_type
because type
is also a python built-in keyword.
self.execute_command(command) | ||
time.sleep(2) | ||
|
||
def startup(self, port_name, direction="bi-directional"): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- I see code duplication in the
startup
andshutdown
method. It hints that the code in these two methods can be extracted into a third private method likeself._update_port_status(self, port_name, status, direction)
. - For the direction argument, it would be better to use enum instead of hard coded string.
- Is it better to get the result of such operations and return it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will take all these into account
|
||
return self.connections | ||
|
||
def create_connection(self, ports): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it better to rename ports
argument to port_pairs
?
self.connections[port1_E] = port2_W | ||
self.connections[port1_W] = port2_E | ||
self.connections[port2_E] = port1_W | ||
self.connections[port2_W] = port1_E |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it better to return result of this operation?
self.connections[port2_E] = port1_W | ||
self.connections[port2_W] = port1_E | ||
|
||
def remove_connection(self, ports): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ports
-> port_pairs
?
pass | ||
|
||
def __str__(self): | ||
return "{ L1 Switch - hostname: '%s', device_type: '%s' }" % (self.hostname, self.type) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The common practice to represent a class is to use < xxx >
.
attempts = 0 | ||
connected_session = False | ||
stdin, stdout, stderr = None, None, None | ||
self.client = self.setup_SSH_connection() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Every time execute_command
is called, it needs to setup a SSH connection. Not really efficient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is required as the SSH command requires a timeout after running every command, and during this timeout the SSH session is lost. The L1 switch is a robotic switch so running each command takes some time.
self.client = None | ||
|
||
def __getattr__(self, module_name): | ||
return getattr(self.host, module_name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume this is for getting an ansible module? However, I don't think this gonna work. When is self.host
initialized?
Description of PR
Summary: With the introduction of L1 switches to SONiC's testing suite, there were no existing APIs available to interact with the L1 switch and use its functionality. This PR introduces new APIs that will allow any user to interact with an L1 switch in the lab, especially for automating connections for the integrated tesbed setup, and during nightly runs.
We introduce 3 primary APIs to interact with the L1 switch in a seamless manner. All APIs have been designed to be idempotent:
Fixes # (issue)
Type of change
Back port request
Approach
What is the motivation for this PR?
The introduction of L1 switches requires a level of automation for automated setup of testbeds for debugging as well as nightly runs that is not available to us currently. This PR provides easily usable APIs that can be used to automate several L1 switch operations such as creating or removing connections.
How did you do it?
Using the paramiko SSH client, commands are able to be run on the remote server i.e. L1 switch from a host server. Created 3 new APIs.
How did you verify/test it?
Ran it on the SONiC L1 Switch
Ran a test script
Output
Logs on the L1 switch
Any platform specific information?
Applicable for the W2W ROME L1 switches
Supported testbed topology if it's a new test case?
Documentation