Open itdependsnetworks opened 7 years ago
This came up from netbox (see above), I am trying to gauge the core teams willingness to allow?
@ktbyers @dbarrosop @mirceaulinic
Great topic, thanks for raising this, Ken.
I like the idea of having the interfaces names normalised (I guess that's one of the few things our getter does not present in a uniform shape).
I fear changing the output of the existing getters, get_interfaces
and get_interfaces_ip
- but not limited to, will be directly affected by this changes, and this comes with a cascade of problems:
But, as I said, I like the idea, and here's what I would suggest:
normalise_interface_name
, that given an interface name having the platform format, returns the NAPALM uniform format, e.g.:>>> d = get_network_driver('junos')
>>> j = d(...)
>>> j.open()
...
>>> j.normalise_interface_name('xe-0/0/0')
TenGigEth0/0/0
(just a dummy return, of course, cause y'all ❤️ crisco)
This would be good for various reasons, for whenever the user needs that. And it would also work well to be invoked in Netbox, or anywhere else. If the user trusts this, they can anyway post-process the output from the NAPALM getters with this and get the output they need.
We can eventually add a flag to the getters in subject, i.e., def get_interfaces(self, normalise_interfaces=False)
.
In time, when we'll consider this helper as being stable enough, we can eventually reconsider if the normalise_interfaces
flag should default to True
. But, in my opinion, this is way too early right now.
Yes, I like what @mirceaulinic proposed here....that sounds like a good solution to this problem.
I think we could also have issues on how do we lookup
the canonical name from the shortened name since the shortened name could have a lot of different potential forms.
Agreed with the approach. I do just want to note, my solution is low impact since it defaults back to the original if there is no match. I use it internally with good results.
The real change (and impact ) is with new results when upgrading.
Would it be sufficient simply to include the port description along with the ID? Here's what we see on a device with an IOS neighbor:
Neighbour Information:
Chassis type : Mac address
Chassis ID : 88:5a:92:4e:12:ff
Port type : Interface name
Port ID : Te1/49
Port description : TenGigabitEthernet1/49
System name : cisco-switch
Here's what NAPALM reports:
"xe-0/0/4": [
{
"hostname": "cisco-switch",
"port": "Te1/49"
}
]
Including the port description should provide the full name, at least for IOS. This would be enough for us over at NetBox, because we could consider a match on either string to indicate a valid connection.
(On the IOS switch I'm looking at, setting a local description on the interface does not appear to change what is reported via LLDP. Junos is less predictable, but it only ever uses one form of interface ID anyway.)
That would be specific to the getter, and my suggestion would be to open an issue against it to be discussed. This method would be across all getters.
I would argue that the issue is still there, in that local interface would still (presumably) be the shortname, depending on vendor implementation.
@jeremystretch yeah, if you want that info you probably should open an issue for discussion. Current get_lldp_neighbors
is quite bare so I wouldn't mind discussing adding more info.
Regarding the whole idea, I like the idea but only partially. If we are to normalize interfaces, which I think we should, I would certainly not use a naming scheme that emulates how Cisco does it because I think it's terrible and basically why we are in this mess. I think basically that interface names should be named after $type$id and that's it. For example:
ethernet1/1
, vlan23
, atm321
, etc. That also means the whole translation is extremely simpler because it's a matter of finding patterns rather than having to map every potential combination. For example, to know it's of ethernet type it would be as simple as:regex = re.compile("(?P<name>(\w|-)*)(?P<id>\d+.*)")
match = regex.match(raw_name)
ifname = match.group('name').lower()
ifid = match.group('id').lower()
ethertypes_start_with = ['gi', 'fa', 'hu', 'xe', ....]
vlans_start_with = ['vl', 'blah', 'bleh', ...]
...
if 'eth' in ifname or ifname[0:2] in ethertypes_start_with:
prefix = "ethernet"
elif 'vlan' in ifname or ifname[0:2] in vlans_start_with:
prefix = "vlan"
...
return "{}.{}".format(prefix, ifid)
Then there is the matter on how to best deploy this and I agree with the plan @mirceaulinic presented but I'd suggest instead to use an optional_arg to enable it for the whole session so the user doesn't have to specify it in every single method.
@dbarrosop I would not suggest using regex here. What is the difference between a POS1
and Po1
as an example (POS vs Port-channel). tbh, this is based on: https://github.com/gitpan/Net-Telnet-Cisco-IOS/blob/374e304db5966fc6362f479dafcfdf88c91f0af7/lib/Net/Telnet/Cisco/IOS.pm#L619 which worked much better than my prior regex attempts.
My intention is to leave it as found in the configuration. I can understand normalizing et, vl, etc... As a value add, but I suspect most use it as I do to have one source of truth of interfaces. In addition, this is a valid cisco config (though both daughter cards never exist at same time)
interface GigabitEthernet1/1/1
!
interface GigabitEthernet1/1/2
!
interface GigabitEthernet1/1/3
!
interface GigabitEthernet1/1/4
!
interface TenGigabitEthernet1/1/1
!
interface TenGigabitEthernet1/1/2
!
What is the difference between a POS1 and Po1
I don't see the problem. In my example code you would have (ifname: pos, id: 1)
and (ifname: po, id: 2)
respectively so it works as expected:
if ifname == 'pos':
# we got pos
elif ifname[0:2] == 'po':
# we got a port-channel
My intention is to leave it as found in the configuration
So the scope is not to normalize but to expand to the longer form of the name?
@dbarrasop correct, should probably adjust the name
Ok, I have no opinion then :P
Normalize Interface
I currently do this in post-processing, but would be nice to have an option to return an normalized interface. This is essentially what I do: https://github.com/itdependsnetworks/Scripts/blob/master/normalize_interface/normalize_interface.py