Python: cycle and setattr

This week a colleague refactor a script that I wrote and the end was pretty different from what I did. The logic was the same but the code was very differnt. I learnt two things about python

setattr: This method provides an alternate means to assign values to class variables, in addition to constructors and object functions. It comes in handy when we want to add a new attribute to an object and assigning it a value
cycle: . This function takes an iterable inputs as an argument and returns an infinite iterator over the values in inputs that returns to the beginning once the end of inputs is reached. 

API scripts: CML and Vsphere

In the last months I have been trying to practice the knowledge from CCNA DevNet and managed to wrote very basic scripts using API.


CML is a simulation solution from Cisco that actually works (you have to pay and need hardware). There are nice docs out there:

CML sandbox

CML Starting guide + API examples (this saved me)

CML simulation lifecycle example (havent tried yet)

CML: I actually struggled in this one regarding how to authenticate….. Checking some pages I worked out. I was trying to use the theory from DevNet but no joy. The idea is to restore a lab after you have made many changes. The script log into CML, delete the lab and restore with a provided backup.


Some docs for vsphere api:

Vsphere create session: (quite useful)

vcenter REST API authentication

vcenter API with Postman

Vsphere postman examples (need to take a look)

Vsphere: This is even simpler…. at least in this one I didnt struggle with the auth as the documentation was quite clear. But the original goal of restore a VM from a snapshot looks like is not available via API.

CCNA DevNet Notes

1) Python Requests status code checks:

r.status_code == requests.codes.ok

2) Docker publish ports:

$ docker run -p 127.0.0.1:80:8080/tcp ubuntu bash

This binds port 8080 of the container to TCP port 80 on 127.0.0.1 of the host machine. You can also specify udp and sctp ports. The Docker User Guide explains in detail how to manipulate ports in Docker.

3) HTTP status codes:

1xx informational
2xx Successful
 201 created
 204 no content (post received by server)
3xx Redirect
 301 moved permanently - future requests should be directed to the given URI
 302 found - requested resource resides temporally under a different URI
 304 not modified
4xx Client Error
 400 bad request
 401 unauthorized (user not authenticated or failed)
 403 forbidden (need permissions)
 404 not found
5xx Server Error
 500 internal server err - generic error message
 501 not implemented
 503 service unavailable

4) Python dictionary filters:

my_dict = {8:'u',4:'t',9:'z',10:'j',5:'k',3:'s'}

# filter(function,iterables)
new_dict = dict(filter(lambda val: val[0] % 3 == 0, my_dict.items()))

print("Filter dictionary:",new_filt)

5) HTTP Authentication

Basic: For "Basic" authentication the credentials are constructed by first combining the username and the password with a colon (aladdin:opensesame), and then by encoding the resulting string in base64 (YWxhZGRpbjpvcGVuc2VzYW1l).

Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l

---
auth_type = 'Basic'
creds = '{}:{}'.format(user,pass)
creds_b64 = base64.b64encode(creds)
header = {'Authorization': '{}{}'.format(auth_type,creds_b64)}

Bearer:

Authorization: Bearer <TOKEN>

6) “diff -u file1.txt file2.txt”. link1 link2

The unified format is an option you can add to display output without any redundant context lines

$ diff -u file1.txt file2.txt                                                                                                            
--- file1.txt   2018-01-11 10:39:38.237464052 +0000                                                                                              
+++ file2.txt   2018-01-11 10:40:00.323423021 +0000                                                                                              
@@ -1,4 +1,4 @@                                                                                                                                  
 cat                                                                                                                                             
-mv                                                                                                                                              
-comm                                                                                                                                            
 cp                                                                                                                                              
+diff                                                                                                                                            
+comm
  • The first file is indicated by —
  • The second file is indicated by +++
  • The first two lines of this output show us information about file 1 and file 2. It lists the file name, modification date, and modification time of each of our files, one per line. 
  • The lines below display the content of the files and how to modify file1.txt to make it identical to file2.txt.
  • - (minus) – it needs to be deleted from the first file.
    + (plus) – it needs to be added to the first file.
  • The next line has two at sign @ followed by a line range from the first file (in our case lines 1 through 4, separated by a comma) prefixed by “-“ and then space and then again followed by a line range from the second file prefixed by “+” and at the end two at sign @. Followed by the file content in output tells us which line remain unchanged and which lines needs to added or deleted(indicated by symbols) in the file 1 to make it identical to file 2

7) Python Testing: Assertions

.assertEqual(a, b)	a == b
.assertTrue(x)	        bool(x) is True
.assertFalse(x)	        bool(x) is False
.assertIs(a, b)	        a is b
.assertIsNone(x)	x is None
.assertIn(a, b)	        a in b
.assertIsInstance(a, b)	isinstance(a, b)

*** .assertIs(), .assertIsNone(), .assertIn(), and .assertIsInstance() all have opposite methods, named .assertIsNot(), and so forth.

Pandas

This is something I have heard about in the past but never used. So this week, as finally decided to write a script to help me to find the peers of flapping ports, learned about pandas from first time. I used another script as “inspiration” and after seeing it was using pandas, I decided to read a bit about it and give it a go.

The main type is the DataFrame. In my head, pandas is just a library to deal with CSV, spreadsheets, etc like when you use a program like libreoffice. And this page, gave me the hints for creating the query I wanted to make.

So at the end I have my very basic script but saves me time logging to each device and find the peer port.

Of course, there are different ways to tackle this problem, but in my environment, the source of truth for links is in a file. You could have that info in the port description too, or in a database, etc.

$ python3 flapping-peer.py -f flapping-list.txt

Result:
SW1 Ethernet1/1 SW2 Ethernet1/1
SW1 Ethernet1/4 SW2 Ethernet1/4

$  
$ cat flapping-list.txt 
SW1,Ethernet1/1
SW2,Ethernet1/4
$
$ cat patching-file.csv 
Site,Source Device,Source Interface,Destination Device,Destination Interface,Media
A,SW1,Ethernet1/1,SW2,Ethernet1/1,SMF
A,SW1,Ethernet1/2,SW2,Ethernet1/2,SMF
A,SW1,Ethernet1/3,SW2,Ethernet1/3,SMF
A,SW1,Ethernet1/4,SW2,Ethernet1/4,SMF
A,SW1,Ethernet1/5,SW2,Ethernet1/5,SMF
$ 

Python Threads

I had to check the reachability of many IPs so I decided to “write” a python script to get this done quickly (yes, I can use nmap but not in this case). I realized that the script was very slow, even just sending two probes…. so I decided to find something else and this was perfect for me. So thanks for the original author as it helped me a lot. I have never tried python threads before so I was quite happy that it worked so smoothly. I adapted for my needs and this is what I have. I remember reading about threads in golang so it helped to understand what it is doing. But likely I will be able to use this as base for more tasks.

As well, I realized that I havent pushed anything in git and that there are extra security layers in place. So I had to create a new token for being able to push my changes to the repo.

Decorators

Trying to make a small change to a python program in my job, I came across something I didnt know in python and only after reading this article (a couple of times) I managed to understand (ask me again in 3 weeks 🙂 The best definition I could find was actually from other blog reference and actually I think it was more clear to me.

“A decorator is a function that takes another function and extends the behavior of the latter function without explicitly modifying it.”

1 – Function returning a function:

In [7]: def greet(name): 
   ...:     return f"Hello, {name}!" 
   ...: def simon(func): 
   ...:     return func("Simon") 
   ...:                                                                                                                       

In [8]: simon(greet)                                                                                                          
Out[8]: 'Hello, Simon!'

simon is a function that has a function as argument, and calls that function with the argument “Simon”. So the function greet is receiving the argument “Simon” and returns a string with that name.

2 – Functions inside other functions:

In [9]: def respect(maybe): 
   ...:     def congrats(): 
   ...:         return "Congrats, bro!" 
   ...:     def insult(): 
   ...:         return "You're silly!" 
   ...:     if maybe == "yes": 
   ...:         return congrats 
   ...:     else: 
   ...:         return insult 
   ...:                                                                                                                       

In [10]: respect("hola")()                                                                                                    
Out[10]: "You're silly!"

In this case, to execute the returned function you need to use “()” at the end (because respect(“hola”) it is a function!): respect(“hola”)()

Keep in mind you return the function “congrats” and it is not executed. If you return “congrats()” then yes, you get the result of executing congrats.

3 – A function that takes another function and defines a function:

In [1]: def startstop(func): 
   ...:     def wrapper(): 
   ...:         print("Starting...") 
   ...:         func() 
   ...:         print("Finished!") 
   ...:     return wrapper 
   ...: def roll(): 
   ...:     print("Rolling on the floor laughing XD") 
   ...: roll = startstop(roll)                                                                                                

In [2]: roll()                                                                                                                
Starting...
Rolling on the floor laughing XD
Finished!

In [3]:        

This case is the same as before, need to use “()” to “execute” roll because it is a function.

4 – With decorator:

In [3]: def startstop(func): 
   ...:     def wrapper(): 
   ...:         print("Starting...") 
   ...:         func() 
   ...:         print("Finished!") 
   ...:     return wrapper 
   ...: @startstop 
   ...: def roll(): 
   ...:     print("Rolling on the floor laughing XD") 
   ...:                                                                                                                       

In [4]: roll()                                                                                                                
Starting...
Rolling on the floor laughing XD
Finished!

In [5]:          

So adding the decorator we avoid writing a line with nested functions. That in a more advanced case, it would make the code easier to read.

You can nest decorators and add arguments too.

python-golang-p1

This week I had to update several spreadsheets…. again donkey job, again try to work smarter. So there was a pattern, and I knew I could copy/paste to the spreadsheet all changes (192 changes per file…). So decided to create a python script to generate the output I needed. It was just new hostnames for devices. So it wasnt really difficult. Although I had to search for basic stuff like how to make a for loop in python. That’s what happens when yo dont use thing often.

Anyway, I managed to get my basic python script. And I could copy paste the output to the spreadsheet just fine.

$ cat rename.py 
for x in range(137,141):
    print("router-p1-r" + str(x) + "01")
    print("router-p1-r" + str(x) + "02")
    print("router-p1-r" + str(x) + "03")
    print()
$ 
$ python rename.py 
router-p1-r13701
router-p1-r13702
router-p1-r13703

router-p1-r13801
router-p1-r13802
router-p1-r13803

router-p1-r13901
router-p1-r13902
router-p1-r13903

router-p1-r14001
router-p1-r14002
router-p1-r14003

But now, I have been trying to learn golang (even though I dont master python neither bash….) and I thought this was a basic stuff to try in golang too. So again, I had to search for basic stuff. How to create a range: link. How to concatenate a string and a integer: link.

So managed to get this and looks like it does the same job:

$ cat rename.go 
package main

import "fmt"

func main() {
	for i := 137; i <= 141; i++ {
		fmt.Println(fmt.Sprint("router-p1-r", i, "01"))
		fmt.Println(fmt.Sprint("router-p1-r", i, "02"))
		fmt.Println(fmt.Sprint("router-p1-r", i, "03"))
		fmt.Println()
	}
}
$ 
$ go run rename.go 
router-p1-r13701
router-p1-r13702
router-p1-r13703

router-p1-r13801
router-p1-r13802
router-p1-r13803

router-p1-r13901
router-p1-r13902
router-p1-r13903

router-p1-r14001
router-p1-r14002
router-p1-r14003

router-p1-r14101
router-p1-r14102
router-p1-r14103

So got the same result in both languages. Keep going!

cEOS Netconf – Ncclient

I am still trying to play with / understand Openconfig/YANG/Netconf modelling. Initially I tried to use ansible to configure EOS via netconf but I didnt get very far 🙁

I have found an Arista blog to deal with netconf using the python library ncclient.

This is my adapted code. Keep in mind that I think there is a typo/bug in Arista blog in “def irbrpc(..)” as it should return “snetrpc” instead of “irbrpc”. This is the error I had:

Traceback (most recent call last):
File "eos-ncc.py", line 171, in
main()
File "eos-ncc.py", line 168, in main
execrpc(hostip, uname, passw, rpc)
File "eos-ncc.py", line 7, in execrpc
rpcreply = conn.dispatch(to_ele(rpc))
File "xxx/lib/python3.7/site-packages/ncclient/xml_.py", line 126, in to_ele
return x if etree.iselement(x) else etree.fromstring(x.encode('UTF-8'), parser=_get_parser(huge_tree))
AttributeError: 'function' object has no attribute 'encode'

After a couple of prints in “ncclient/xml_.py” I could see “x” was a function but I couldnt understand why. Just by chance I notices the typo in the return.

As well, I couldn’t configure the vxlan interface using XML as per the blog and I had to remove it and add it via a RPC call with CLI commands “intfrpcvxlan_cli”. This is the error I had:

Traceback (most recent call last):
File "eos-ncc.py", line 171, in
main()
File "eos-ncc.py", line 168, in main
execrpc(hostip, uname, passw, rpc)
File "eos-ncc.py", line 7, in execrpc
rpcreply = conn.dispatch(to_ele(rpc))
File "xxx/lib/python3.7/site-packages/ncclient/manager.py", line 236, in execute
huge_tree=self._huge_tree).request(*args, **kwds)
File "xxx/lib/python3.7/site-packages/ncclient/operations/retrieve.py", line 239, in request
return self._request(node)
File "xxx/lib/python3.7/site-packages/ncclient/operations/rpc.py", line 348, in _request
raise self._reply.error
ncclient.operations.rpc.RPCError: Request could not be completed because leafref at path "/interfaces/interface[name='Vxlan1']/name" had error "leaf value (Vxlan1) not present in reference path (../config/name)"

So in my script, I make two calls and print the reply:

$ python eos-ncc.py
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="urn:uuid:7b1be88e-36b7-4289-a0d2-396a0f21cf5e"><ok></ok></rpc-reply>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="urn:uuid:750a50be-3534-442b-bad4-2f8c916afd77"><ok></ok></rpc-reply>

And this is what the logs show:

## first rpc call
2020-08-13T12:52:41.937079+00:00 r01 ConfigAgent: %SYS-5-CONFIG_SESSION_ENTERED: User tomas entered configuration session session630614618267084 on NETCONF (172.27.0.1)
2020-08-13T12:52:42.302111+00:00 r01 ConfigAgent: %SYS-5-CONFIG_SESSION_COMMIT_SUCCESS: User tomas committed configuration session session630614618267084 successfully on NETCONF (172.27.0.1)
2020-08-13T12:52:42.302928+00:00 r01 ConfigAgent: %SYS-5-CONFIG_SESSION_EXITED: User tomas exited configuration session session630614618267084 on NETCONF (172.27.0.1)
2020-08-13T12:52:42.325878+00:00 r01 Launcher: %LAUNCHER-6-PROCESS_START: Configuring process 'HostInject' to start in role 'ActiveSupervisor'
2020-08-13T12:52:42.334151+00:00 r01 Launcher: %LAUNCHER-6-PROCESS_START: Configuring process 'ArpSuppression' to start in role 'ActiveSupervisor'
2020-08-13T12:52:42.369660+00:00 r01 Ebra: %LINEPROTO-5-UPDOWN: Line protocol on Interface Vlan100 (VLAN_100), changed state to up
2020-08-13T12:52:42.527568+00:00 r01 ProcMgr-worker: %PROCMGR-6-WORKER_WARMSTART: ProcMgr worker warm start. (PID=553)
2020-08-13T12:52:42.557663+00:00 r01 ProcMgr-worker: %PROCMGR-7-NEW_PROCESSES: New processes configured to run under ProcMgr control: ['ArpSuppression', 'HostInject']
2020-08-13T12:52:42.570208+00:00 r01 ProcMgr-worker: %PROCMGR-7-PROCESSES_ADOPTED: ProcMgr (PID=553) adopted running processes: (SharedSecretProfile, PID=1024) (Lldp, PID=832) (SlabMonitor, PID=555) (Pim, PID=1156) (MplsUtilLsp, PID=902) (Mpls, PID=903) (Isis, PID=1087) (PimBidir, PID=1164) (Igmp, PID=1172) (Acl, PID=920) (StaticRoute, PID=1060) (IgmpSnooping, PID=1030) (IpRib, PID=1064) (Stp, PID=939) (KernelNetworkInfo, PID=940) (Etba, PID=1073) (KernelMfib, PID=1139) (ConnectedRoute, PID=1076) (RouteInput, PID=1080) (EvpnrtrEncap, PID=1082) (McastCommon6, PID=956) (ConfigAgent, PID=702) (Fru, PID=703) (Launcher, PID=704) (Bgp, PID=1089) (McastCommon, PID=834) (SuperServer, PID=836) (OpenConfig, PID=839) (LacpTxAgent, PID=970) (AgentMonitor, PID=845) (Snmp, PID=848) (PortSec, PID=850) (Ira, PID=852) (IgmpHostProxy, PID=1146) (EventMgr, PID=862) (Sysdb, PID=607) (CapiApp, PID=866) (Arp, PID=995) (StpTxRx, PID=871) (KernelFib, PID=1000) (StageMgr, PID=700) (Lag, PID=876) (Qos, PID=1005) (L2Rib, PID=1008) (PimBidirDf, PID=1137) (Tunnel, PID=883) (PimBsr, PID=1150) (Msdp, PID=1142) (BgpCliHelper, PID=1067) (TopoAgent, PID=1017) (Aaa, PID=890) (StpTopology, PID=891) (Ebra, PID=1022) (ReloadCauseAgent, PID=1023)
2020-08-13T12:52:42.586632+00:00 r01 ProcMgr-worker: %PROCMGR-6-PROCESS_STARTED: 'HostInject' starting with PID=23450 (PPID=553) -- execing '/usr/bin/HostInject'
2020-08-13T12:52:42.604711+00:00 r01 ProcMgr-worker: %PROCMGR-7-WORKER_WARMSTART_DONE: ProcMgr worker warm start done. (PID=553)
2020-08-13T12:52:42.604786+00:00 r01 ProcMgr-worker: %PROCMGR-6-PROCESS_STARTED: 'ArpSuppression' starting with PID=23452 (PPID=553) -- execing '/usr/bin/ArpSuppression'
2020-08-13T12:52:42.749880+00:00 r01 HostInject: %AGENT-6-INITIALIZED: Agent 'HostInject' initialized; pid=23453
2020-08-13T12:52:43.102567+00:00 r01 ArpSuppression: %AGENT-6-INITIALIZED: Agent 'ArpSuppression' initialized; pid=23452

## second rpc call
2020-08-13T12:52:43.250995+00:00 r01 ConfigAgent: %SYS-5-CONFIG_SESSION_ENTERED: User tomas entered configuration session session630615932519210 on NETCONF (172.27.0.1)
2020-08-13T12:52:43.465035+00:00 r01 ConfigAgent: %SYS-5-CONFIG_SESSION_COMMIT_SUCCESS: User tomas committed configuration session session630615932519210 successfully on NETCONF (172.27.0.1)
2020-08-13T12:52:43.466480+00:00 r01 ConfigAgent: %SYS-5-CONFIG_SESSION_EXITED: User tomas exited configuration session session630615932519210 on NETCONF (172.27.0.1)
2020-08-13T12:52:43.472728+00:00 r01 Launcher: %LAUNCHER-6-PROCESS_START: Configuring process 'VxlanSwFwd' to start in role 'ActiveSupervisor'
2020-08-13T12:52:43.475470+00:00 r01 Launcher: %LAUNCHER-6-PROCESS_START: Configuring process 'Vxlan' to start in role 'ActiveSupervisor'
2020-08-13T12:52:43.674498+00:00 r01 ProcMgr-worker: %PROCMGR-6-WORKER_WARMSTART: ProcMgr worker warm start. (PID=553)
2020-08-13T12:52:43.701854+00:00 r01 ProcMgr-worker: %PROCMGR-7-NEW_PROCESSES: New processes configured to run under ProcMgr control: ['Vxlan', 'VxlanSwFwd']
2020-08-13T12:52:43.714484+00:00 r01 ProcMgr-worker: %PROCMGR-7-PROCESSES_ADOPTED: ProcMgr (PID=553) adopted running processes: (SharedSecretProfile, PID=1024) (Lldp, PID=832) (SlabMonitor, PID=555) (Pim, PID=1156) (MplsUtilLsp, PID=902) (Mpls, PID=903) (Isis, PID=1087) (PimBidir, PID=1164) (Igmp, PID=1172) (Acl, PID=920) (HostInject, PID=23450) (ArpSuppression, PID=23452) (StaticRoute, PID=1060) (IgmpSnooping, PID=1030) (IpRib, PID=1064) (Stp, PID=939) (KernelNetworkInfo, PID=940) (Etba, PID=1073) (KernelMfib, PID=1139) (ConnectedRoute, PID=1076) (RouteInput, PID=1080) (EvpnrtrEncap, PID=1082) (McastCommon6, PID=956) (ConfigAgent, PID=702) (Fru, PID=703) (Launcher, PID=704) (Bgp, PID=1089) (McastCommon, PID=834) (SuperServer, PID=836) (OpenConfig, PID=839) (LacpTxAgent, PID=970) (AgentMonitor, PID=845) (Snmp, PID=848) (PortSec, PID=850) (Ira, PID=852) (IgmpHostProxy, PID=1146) (EventMgr, PID=862) (Sysdb, PID=607) (CapiApp, PID=866) (Arp, PID=995) (StpTxRx, PID=871) (KernelFib, PID=1000) (StageMgr, PID=700) (Lag, PID=876) (Qos, PID=1005) (L2Rib, PID=1008) (PimBidirDf, PID=1137) (Tunnel, PID=883) (PimBsr, PID=1150) (Msdp, PID=1142) (BgpCliHelper, PID=1067) (TopoAgent, PID=1017) (Aaa, PID=890) (StpTopology, PID=891) (Ebra, PID=1022) (ReloadCauseAgent, PID=1023)
2020-08-13T12:52:43.731810+00:00 r01 ProcMgr-worker: %PROCMGR-6-PROCESS_STARTED: 'Vxlan' starting with PID=23482 (PPID=553) -- execing '/usr/bin/Vxlan'
2020-08-13T12:52:43.746053+00:00 r01 ProcMgr-worker: %PROCMGR-7-WORKER_WARMSTART_DONE: ProcMgr worker warm start done. (PID=553)
2020-08-13T12:52:43.746199+00:00 r01 ProcMgr-worker: %PROCMGR-6-PROCESS_STARTED: 'VxlanSwFwd' starting with PID=23484 (PPID=553) -- execing '/usr/bin/VxlanSwFwd'
2020-08-13T12:52:43.942447+00:00 r01 VxlanSwFwd: %AGENT-6-INITIALIZED: Agent 'VxlanSwFwd' initialized; pid=23487
2020-08-13T12:52:43.974473+00:00 r01 Vxlan: %AGENT-6-INITIALIZED: Agent 'Vxlan' initialized; pid=23485
2020-08-13T12:52:44.310150+00:00 r01 Launcher: %LAUNCHER-6-PROCESS_START: Configuring process 'Fhrp' to start in role 'AllSupervisors'
2020-08-13T12:52:44.512110+00:00 r01 ProcMgr-worker: %PROCMGR-6-WORKER_WARMSTART: ProcMgr worker warm start. (PID=553)
2020-08-13T12:52:44.538052+00:00 r01 ProcMgr-worker: %PROCMGR-7-NEW_PROCESSES: New processes configured to run under ProcMgr control: ['Fhrp']
2020-08-13T12:52:44.550918+00:00 r01 ProcMgr-worker: %PROCMGR-7-PROCESSES_ADOPTED: ProcMgr (PID=553) adopted running processes: (SharedSecretProfile, PID=1024) (Lldp, PID=832) (SlabMonitor, PID=555) (Pim, PID=1156) (MplsUtilLsp, PID=902) (Mpls, PID=903) (Isis, PID=1087) (PimBidir, PID=1164) (Igmp, PID=1172) (Acl, PID=920) (HostInject, PID=23450) (ArpSuppression, PID=23452) (StaticRoute, PID=1060) (IgmpSnooping, PID=1030) (IpRib, PID=1064) (Stp, PID=939) (KernelNetworkInfo, PID=940) (Vxlan, PID=23482) (Etba, PID=1073) (KernelMfib, PID=1139) (ConnectedRoute, PID=1076) (RouteInput, PID=1080) (EvpnrtrEncap, PID=1082) (McastCommon6, PID=956) (ConfigAgent, PID=702) (Fru, PID=703) (Launcher, PID=704) (Bgp, PID=1089) (McastCommon, PID=834) (SuperServer, PID=836) (OpenConfig, PID=839) (LacpTxAgent, PID=970) (AgentMonitor, PID=845) (Snmp, PID=848) (PortSec, PID=850) (Ira, PID=852) (IgmpHostProxy, PID=1146) (EventMgr, PID=862) (Sysdb, PID=607) (CapiApp, PID=866) (Arp, PID=995) (StpTxRx, PID=871) (KernelFib, PID=1000) (StageMgr, PID=700) (VxlanSwFwd, PID=23484) (Lag, PID=876) (Qos, PID=1005) (L2Rib, PID=1008) (PimBidirDf, PID=1137) (Tunnel, PID=883) (PimBsr, PID=1150) (Msdp, PID=1142) (BgpCliHelper, PID=1067) (TopoAgent, PID=1017) (Aaa, PID=890) (StpTopology, PID=891) (Ebra, PID=1022) (ReloadCauseAgent, PID=1023)
2020-08-13T12:52:44.565230+00:00 r01 ProcMgr-worker: %PROCMGR-7-WORKER_WARMSTART_DONE: ProcMgr worker warm start done. (PID=553)
2020-08-13T12:52:44.565339+00:00 r01 ProcMgr-worker: %PROCMGR-6-PROCESS_STARTED: 'Fhrp' starting with PID=23491 (PPID=553) -- execing '/usr/bin/Fhrp'
2020-08-13T12:52:44.720343+00:00 r01 Fhrp: %AGENT-6-INITIALIZED: Agent 'Fhrp' initialized; pid=23493

I still would like to be able to get the full config via netconf. Just copy/paste the rpc in the ssh shell (like juniper) or maybe using ydk like this. And keep dreaming, to be able to fully configure the switch via netconf/ansible.

Vim + Python Linters

I was reading an article about tools to write python using VIM with good formatting. I am not a pro-user of VIM neither a pro-python programmer but I would like to be more efficient and write better formatted python code.

So this is the link I was reading and ended here for the specific details.

At the end, my goal is to use more often inside VIM: splits (:sp), nerdtree (file browsing), autocompletion, git and be sure my code is formatted automatically if I make a mistake.

So I enabled most of the plugins from the article although I made some tweaks for me normal usage (I already had enabled some pluggins for jinja2). This is my .vimrc:

set nocompatible              " be iMproved, required
filetype off                  " required

" set the runtime path to include Vundle and initialize
set rtp+=~/.vim/bundle/Vundle.vim

" https://realpython.com/vim-and-python-a-match-made-in-heaven/#syntax-checkinghighlighting
set splitbelow
set splitright
"split navigations
nnoremap  
nnoremap  
nnoremap  
nnoremap  

" Enable folding
set foldmethod=indent
set foldlevel=99
" Enable folding with the spacebar
nnoremap  za

" Automatic formating for tab, whitespace and max 80 chars per line, etc
au BufNewFile,BufRead *.py
    \ set tabstop=4 |
    \ set softtabstop=4 |
    \ set shiftwidth=4 |
    \ set textwidth=79 |
    \ set expandtab |
    \ set autoindent |
    \ set fileformat=unix

highlight BadWhitespace ctermbg=red guibg=darkred
au BufRead,BufNewFile *.py,*.pyw,*.c,*.h match BadWhitespace /\s\+$/

set encoding=utf-8

let python_highlight_all=1

" VUNDLE PLUGINGS

call vundle#begin()
" alternatively, pass a path where Vundle should install plugins
" call vundle#begin('~/some/path/here')

" let Vundle manage Vundle, required
Plugin 'VundleVim/Vundle.vim'
" added nerdtree
Plugin 'scrooloose/nerdtree'

Plugin 'ctrlp.vim'

Plugin 'Jinja'

Plugin 'tmhedberg/SimpylFold'

Plugin 'vim-scripts/indentpython.vim'

Plugin 'vim-syntastic/syntastic'

Plugin 'nvie/vim-flake8'

Plugin 'tpope/vim-fugitive'

Plugin 'Lokaltog/powerline', {'rtp': 'powerline/bindings/vim/'}

" Keep Plugin commands between vundle#begin/end.
" All of your Plugins must be added before the following line
call vundle#end()            " required



filetype plugin indent on    " required
syntax on

nmap  :NERDTreeToggle

" To ignore plugin indent changes, instead use:
"filetype plugin on
"
" Brief help
" :PluginList       - lists configured plugins
" :PluginInstall    - installs plugins; append `!` to update or just :PluginUpdate
" :PluginSearch foo - searches for foo; append `!` to refresh local cache
" :PluginClean      - confirms removal of unused plugins; append `!` to auto-approve removal
"
" see :h vundle for more details or wiki for FAQ
" Put your non-Plugin stuff after this line


au BufNewFile,BufRead *.lmx set filetype=xml
au BufNewFile,BufRead *.dump set filetype=sql
au BufNewFile,BufRead *.j2 set filetype=jinja

"for case-insensitve searches"
set ignorecase

"Override the 'ignorecase' option if the search pattern contains upper"
"case characters.  Only used when the search pattern is typed and"
"'ignorecase' option is on."
set smartcase

" I want to be able to resize the splits quickly so I want the mouse on
set mouse=a

" Always show statusline - This makes powerline always on
set laststatus=2

" autocmd vimenter * NERDTree

BTW, a quick reference for NerdTree (file browser) here.

Let’s see how I get on with these changes.