Skip to content
This repository has been archived by the owner on Nov 10, 2023. It is now read-only.

Code dup #33

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open

Code dup #33

wants to merge 13 commits into from

Conversation

Ali-aqrabawi
Copy link

Description

code refactoring:

  1. added new module connection:
    which has the protocol connection classes like ssh, telnet and serial.
    this approach is needed to split the business logic from external libraries , so we can easily change libraries without changing our code. also this is needed to add different connection types.

  2. added terminal_modes module:
    objects that handle entering and exiting from different terminal modes like config_mode , enable_mode ... etc.
    this approach is to eliminate code duplication in the Devices classes.

those are the major changes,
there are some changes on the device level, like adding methods, removing methods ... etc.

a new main method added to BaseDevice is _session_preparation , which will be called to prepare each device session.

new features:

  1. telnet support.
  2. textfsm.

@selfuryon selfuryon self-assigned this May 18, 2019
@selfuryon
Copy link
Owner

Thank you for refactoring the code!
I'm going to test it this weekend and plan to merge it on Monday if all is fine!

@Ali-aqrabawi
Copy link
Author

Thanks, please note that this pr has vt100 as term_mod, you can change it from constants.py module.

@selfuryon
Copy link
Owner

If I have any problems with that on Mikrotik I think I change it only for Mikrotik.
I test it separately. Thank you for the information!

Copy link
Owner

@selfuryon selfuryon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello!
Some notes about the code

netdev/contants.py Outdated Show resolved Hide resolved
netdev/_textfsm/_clitable.py Outdated Show resolved Hide resolved
netdev/_textfsm/_clitable.py Outdated Show resolved Hide resolved
netdev/_textfsm/_clitable.py Outdated Show resolved Hide resolved
netdev/_textfsm/_terminal.py Outdated Show resolved Hide resolved
netdev/connections/interface.py Outdated Show resolved Hide resolved
netdev/connections/base.py Show resolved Hide resolved
netdev/connections/ssh.py Outdated Show resolved Hide resolved
netdev/vendors/devices/base.py Outdated Show resolved Hide resolved
netdev/vendors/devices/base.py Show resolved Hide resolved
@Ali-aqrabawi
Copy link
Author

Ali-aqrabawi commented May 18, 2019

@selfuryon please have a look at the updated pr.
you need to pip install textfsm before running the code, i could not find requirements.txt file to add it.

@selfuryon
Copy link
Owner

@selfuryon please have a look at the updated pr.
you need to pip install textfsm before running the code, I could not find requirements.txt file to add it.

Yeah, I switched to use poetry for building the project and for dependency management. You can add it to pyproject.toml. This file is used not only poetry right now. You can find more information about that in PEP517 and PEP518

@selfuryon
Copy link
Owner

Thanks for new commits! I'll check it more deeply tomorrow!

Copy link
Owner

@selfuryon selfuryon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some notes.
Today I'm going to perform full testing for all devices what I have.

self._conn.close()
await self._conn.wait_closed()

def send(self, cmd):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have some differences here.
Code here is def send(self, cmd), but in parent class is async def send(self, cmd). We need to do the same for removing the ambiguous.
I think that we can leave it a regular function like asyncssh's authors and asyncio's authors made it


def __check_session(self):
if not self._stdin:
raise RuntimeError("SSH session not started")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to correct it from "SSH session" to "Telnet Session"

""" Establish Telnet Connection """
self._logger.info("Host {}: telnet: Establishing Telnet Connection on port {}".format(self._host, self._port))
try:
self._stdout, self._stdin = await asyncio.open_connection(self._host, self._port, family=0, flags=0)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In SSH we have this code:

        fut = asyncssh.connect(**self._conn_dict)
        try:
            self._conn = await asyncio.wait_for(fut, self._timeout)

So we can manage the timeout for this operation. But when we use telnet we can't. I think we should use the same approach like in SSH

self._conn.close()
await self._conn.wait_closed()

def send(self, cmd):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same thing like in here.
I'd prefer to leave it as a regular function, not a coroutine.

@@ -30,7 +29,7 @@ class ArubaAOS6(IOSLikeDevice):

For Aruba AOS 6 devices base_pattern is "(prompt) (\(.*?\))?\s?[#|>]
"""
logger.info("Host {}: Setting base prompt".format(self._host))
self._logger.info("Host {}: Setting base prompt".format(self.host))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an interesting thing here. In BaseConnection we use self._host format but in BaseDevice we use self.host format. Maybe we should unify it?
If we want to use self.host should we use the same format for port, protocol and so on?


self.current_terminal = None # State Machine for the current Terminal mode of the session

self.enable_mode = EnableMode(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should transfer the default parameters like enter_command, _priv_enter and so on to EnableMode and ConfigMode classes.
This class shouldn't contain any related commands for different terminal modes.

I don't think that the user needs to correct this because they are constants for particular devices.


async def _session_preparation(self):
await super()._session_preparation()
await self.enable_mode()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be self.enable_mode.enter()?
I saw that you use this code for BaseTerminalMode:

async def __call__(self):                                                                                                                          
    """ callable terminal to enter """                                                                                                             
    return await self.enter() 

But I think it too ambiguously: I tried to search a function but I know that it's a class. it may confuse others

return ""

# Send config commands
output = await self.config_mode()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be self.config_mode.enter()?
The same thing like here

output += await super().send_config_set(config_commands=config_commands)

if exit_config_mode:
output += await self.config_mode.exit()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See, we use directly self.config_mode.exit(), but for entering we use self.config_mode() instead of self.config_mode.enter().
It confuses.


if exit_config_mode:
output += await self.exit_config_mode()
output += await self.config_mode.exit()

output = self._normalize_linefeeds(output)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should transfer the normalize_linefeeds function to BaseConnection?
It's a very common function and it's related to a connection not to a device

@Ali-aqrabawi
Copy link
Author

please check updated pr

@selfuryon
Copy link
Owner

I have some problems with HP Comware in testing. Need to go deeper

@selfuryon
Copy link
Owner

Hello!
I think for more than 2 weeks about the structure of code from this PR.
It's a good new structure and new approaches but it still has some lack of isolation which can confuse.

As example:

  • We have a duplication for device hierarchy in vendor and terminal_modes folders: both have cisco, hp, and others
  • Terminal modes classes have a link to a device class and vice versa. They call the other one in their work
  • There are exist a send_command in both classes terminal mode and device
  • All constants for terminal modes still are included in the device class
  • Device class tracks current terminal mode
  • We still have a three level of inheritance

So I decided to get your idea, take some techniques and class and make a refactor for the module in a slight different another way (see #34)

@Ali-aqrabawi
Copy link
Author

make sense, looking forward to see the new structure.

@rishrapsody
Copy link

is there any way to get structured output using asyncssh netdev library?
it seems asyncio is not compatible with netconf?
Please provide a way to get structured output using asyncio netdev. I am trying to run this on Juniper vMX devices

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants