Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
32 changes: 32 additions & 0 deletions config/check_acl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""
Config script to ensure an ACL of the given name exists on the provided interface when ACL related configuration is committed
"""

import cisco.config_validation as xr

from cisco.script_mgmt import xrlog
syslog = xrlog.getSysLogger('check_acl')

#These values should be changed as necessary
interface_name = "TenGigE0/0/0/10"
acl_name = "access-list-1"

def check_acl(root):
#Get the interface with the given name
int_config = root.get_node("/ifmgr-cfg:interface-configurations/interface-configuration[active='act',interface-name='%s']" %interface_name)
if int_config:
syslog.info("Interface found")

#Retrieve the list of ACLs under the interface
acl = int_config.get_list("/ip-pfilter-cfg:ipv4-packet-filter/inbound/acl-name-array")
if acl:
syslog.info("ACL list found")

#Search for the ACL in the list
if acl_name in [x.value for x in acl]:
syslog.info("ACL found")
else:
syslog.error("ACL not found")

#Run script when ACL related config is pushed
xr.register_validate_callback(["/ifmgr-cfg:interface-configurations/ifmgr-cfg:interface-configuration/ip-pfilter-cfg:ipv4-packet-filter/*"], check_acl)
29 changes: 29 additions & 0 deletions config/check_bgp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""
Config script to set a BGP router id when any BGP configuration is committed.
"""
import cisco.config_validation as xr
from cisco.script_mgmt import xrlog

syslog = xrlog.getSysLogger('check_bgp')

#These should be edited to match desired values
instance_name = "default"
instance_as = 0
four_byte_as = 100
router_id = "10.1.1.1"

def check_bgp(root):

#Gets the autonomous system related to the BGP instance
aut_sys = root.get_node("/ipv4-bgp-cfg:bgp/instance[instance-name='%s']/instance-as[as=%i]/four-byte-as[as=%i]/default-vrf" %(instance_name, instance_as, four_byte_as))
if aut_sys:
syslog.info("AS found")

#Set the global BGP router id
aut_sys.set_node("/global/router-id", router_id)
syslog.info("New router id: %s" %aut_sys.get_node("/global/router-id").value)
else:
syslog.info("AS not found")

#Run this script when any BGP related commit is pushed
xr.register_validate_callback(["/ipv4-bgp-cfg:bgp/instance/instance-as/*"], check_bgp)
62 changes: 62 additions & 0 deletions config/check_ospf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""
Config script to check if certain ospf characteristics match desired values

"""


import cisco.config_validation as xr

from cisco.script_mgmt import xrlog

syslog = xrlog.getSysLogger('check_ospf')

#These values should be adjusted as seen fit
area_to_check = 0
process_name = "100"
interface_name = "TenGigE0/0/0/2"
hello_interval_req = 30
cost_minimum = 5

def check_ospf(root):

#The ospf area to check
area = root.get_node("/ipv4-ospf-cfg:ospf/processes/process[process-name='%s']/default-vrf/area-addresses/area-area-id[area-id=%i]" %(process_name, area_to_check))

#If the area exists
if area:
syslog.info("Area %s found" %area_to_check)

#The given interface to check
interface = area.get_node("/name-scopes/name-scope[interface-name='%s']" %interface_name)
if interface:
syslog.info("Interface %s found" %interface_name)

#Get the leaf node representing the cost of the path
curr_cost = interface.get_node("/cost")

#If the cost has been previously set
if curr_cost:
syslog.info("Current cost is %s" %curr_cost.value)

#Check to see if the cost is less than the minimum
if curr_cost.value < cost_minimum:
xr.add_error(curr_cost, "Cost cannot be lower than %s" %cost_minimum) #Throw error

#Get the leaf node representing the hello interval
curr_hello_interval = interface.get_node("/hello-interval")
if curr_hello_interval:
syslog.info("Current hello interval is %s seconds" %curr_hello_interval.value)

#Check the value of the hello interval
if curr_hello_interval.value != hello_interval_req:
curr_hello_interval.set_node(None, hello_interval_req) #set the hello interval
syslog.info("Hello interval set to %s seconds" %hello_interval_req)

#If the hello interval isn't previosly set
else:
syslog.info("No hello interval set previously, now set to %s seconds" %hello_interval_req)
interface.set_node("/hello-interval", hello_interval_req) #set the hello interval


#Only run the script if an ospf process is changed
xr.register_validate_callback(["/ipv4-ospf-cfg:ospf/processes/*"], check_ospf)
63 changes: 63 additions & 0 deletions exec/test_ospf_neighbors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""
How to run:
Use proper aaa settings:
aaa authorization exec default group tacacs+ local
aaa authorization eventmanager default local
aaa authentication login default group tacacs+ local

script add exec /harddisk: test_ospf_neighbors.py
conf

script exec test_ospf_neighbors.py checksum sha256sum <sum>
commit
end

script run test_ospf_neighbors.py arguments <router-id> <interface> '--process' <process #> '--area' <area #>

Example:
script run test_ospf_neighbors.py arguments '10.1.1.4' 'HundredGigE0/0/0/32'
or
script run test_ospf_neighbors.py arguments '10.1.1.4' 'HundredGigE0/0/0/32' '--process' 100 '--area' 0

How to verify:
show logging last 10
check for 'SCRIPT : Configuration succeeded'
"""
import argparse
from iosxr.xrcli.xrcli_helper import *
from cisco.script_mgmt import xrlog

syslog = xrlog.getSysLogger('OSPF neighbor configuration')
helper = XrcliHelper(debug = True)

def ospf_neighbors():
parser = argparse.ArgumentParser()

#optional and positional arguments
parser.add_argument("routerid", help = "ip address of router", type = str)
parser.add_argument("interface", help = "interface for OSPF configuration", type = str)
parser.add_argument("--process", help = "process for OSPF configuration", type = int, default = 100)
parser.add_argument("--area", help = "area for OSPF configuration", type = int, default = 0)
args = parser.parse_args()
router_id = args.routerid
interface_name = args.interface
process_id = args.process
area_id = args.area

#This is identical to issuing the following commands in the configuration terminal
#(config) router ospf <process_number>
#(config-ospf) router-id <routerid>
#(config-ospf) area <area> interface <interface>
#(config-ospf-ar-if) network point-to-point
#(config-ospf-ar-if) commit

result = helper.xr_apply_config_string("router ospf %s \n\r router-id %s \n\r area %s interface %s \n\r network point-to-point" %(process_id, router_id, area_id, interface_name))

#print status messages to syslogx
if result['status'] == 'success':
syslog.info('SCRIPT : Configuration succeeded')
else:
syslog.error('SCRIPT : Configuration failed')

if __name__ == '__main__':
ospf_neighbors()
141 changes: 141 additions & 0 deletions process/test_alarm_process.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
"""
Process script to monitor the number of alarms present on the router

Email notification will be sent when this number changes using Cisco SMTP server

Must be connected to Cisco network for emailing capabilities to function properly

To trigger script
Step 1: Add and configure script as shown in README.MD

Step 2: Register the application with Appmgr

Configuraton:
appmgr process-script my-process-app
executable test_process.py
run-args <threshold-value>

Step 3: Activate the registered application
appmgr process-script activate name my-process-app

"""



import time
import os
import xmltodict
import re


#For emailing functions
import smtplib as SMTP
from email.mime.text import MIMEText

#For logging
from cisco.script_mgmt import xrlog
from iosxr.netconf.netconf_lib import NetconfClient

log = xrlog.getScriptLogger('Alarm')
syslog = xrlog.getSysLogger('Alarm')

def check_curr_alarm_num(prev_count):
"""
Checks current number of alarms
"""
curr_count = 0
filter_string = """
<alarms xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-alarmgr-server-oper">
<detail>
<detail-system>
<stats>
<reported/>
</stats>
</detail-system>
</detail>
</alarms>"""

nc = NetconfClient(debug=True)
nc.connect() #Connects the NetconfClient
do_get(nc, filter=filter_string) #Makes a Netconf get call
ret_dict = _xml_to_dict(nc.reply, 'alarms') #Parses the data from the Netconf Reply into a dictionary format for easy retrieval
curr_count = int(ret_dict['alarms']['detail']['detail-system']['stats']['reported']) #Retrieves number of alamrs from the created dictionary
count_file = open("count.txt", "wt")
count_file.write("Current number of alarms: %s \n" %curr_count) #Writes number of alarms to file
count_file.close()
if curr_count != prev_count: #Checks number of alarms compared to previous number
syslog.error("New Alarm Detected: new count = %s, old count = %s" %(curr_count, prev_count)) #If the number is different, print a syslog error
_send_email(curr_count, prev_count) #Send an email notifying network monitor
nc.close() #Close the Netconf client


def _send_email(curr_count, prev_count):
SMTP_server = 'outbound.cisco.com'
sender = 'epickhar@cisco.com'
dest = 'epickhar@cisco.com'

text_subtype = 'plain'


#Email contents
content = """\
NEW ALARM DETECTED: NEW COUNT = %s, OLD COUNT = %s
""" %(curr_count, prev_count)

subject = "Alarm Change Detected"
msg = MIMEText(content, text_subtype)
msg['Subject'] = subject
msg['From'] = sender

#Connect to SMTP server with port number
conn = SMTP.SMTP(SMTP_server, 25)
conn.set_debuglevel(False)

#Send email
try:
conn.sendmail(sender, dest, msg.as_string())
except:
syslog.error("Message Failed to Send")
finally:
conn.quit()

def _xml_to_dict(xml_output, xml_tag=None):
"""
convert netconf rpc request to dict
:param xml_output:
:return:
"""
if xml_tag:
pattern = "<data>\s+(<%s.*</%s>).*</data>" % (xml_tag, xml_tag)
else:
pattern = "(<data>.*</data>)"
xml_output = xml_output.replace('\n', ' ')
xml_data_match = re.search(pattern, xml_output)
ret_dict = xmltodict.parse(xml_data_match.group(1))
return ret_dict

def do_get(nc, filter=None, path=None):
"""
makes netconf rpc get request
:param nc: Netconf client
:return bool if request successful:
"""
try:
if path is not None:
nc.rpc.get(file=path)
elif filter is not None:
nc.rpc.get(request=filter)
else:
return False
except Exception as e:
return False
return True

if __name__ == '__main__':
prev_count = 0
while(1): #Process script, run continuously
check_curr_alarm_num(prev_count)
count_file = open("count.txt", "rt") #Get the previous count from the file
prev_count = int(count_file.readline()[26:]) #Parse data
count_file.close() #Close file
time.sleep(60) #Run every minute