This example script detects configuration changes and sends emails notifications about those changes.
Sending Email notifications
This tutorial will teach you to create an email notification using NAE.
This script collects information, packages it up, and sends it out as an email to a specified list of recipients.
Documentation for the SMTP Python library can be found here.
Documentation for the email and MIME Python library can be found here.
Documentation for the html Python library can be found here.
To prepare, we import the necessary libraries that are not already part of NAE.
For example:
from smtplib import SMTP
from email.mime.text import MIMEText
from html import escape
Adding the parameters
Step one is to add the required information to the ParameterDefinitions section of the script.
These parameters are used by the agent to connect to the SMTP server and construct the email.
This includes fields such as the SMTP server address and access credentials, as well as email template information including the sender address, recipient address, and subject line.
For example:
ParameterDefinitions = {
'smtp_server_address': {
'Name': 'IP address/hostname and port number of the SMTP server',
'Description': 'Enter the hostname/port number of the SMTP server'
' in the format server_hostname:port. If the port'
' number is not provided , the default port of 25 '
' will be used.',
'Type': 'string',
'Default': ''
},
'sender_email_address': {
'Name': '[Optional] Email address from which the alert is sent',
'Description': 'Enter the email address from which the notification'
' is to be sent. If this value is not provided the'
'default value of admin@{switch_host_name} will be '
'used.',
'Type': 'string',
'Default': ''
},
'recipient_email_address': {
'Name': 'Comma separated list of email addresses to which the '
'notification is to be sent.',
'Description': 'Enter a comma separated list of email addresses to '
'which the email alert notification is to be sent.',
'Type': 'string',
'Default': '',
},
'smtp_server_user_id': {
'Name': '[Optional] User name for SMTP server if protected '
'with credentials',
'Description': 'Enter the user name for the SMTP server if protected'
' with password. It is optional and can be left empty '
'if not protected with username and password.',
'Type': 'string',
'Default': '',
},
'smtp_server_user_password': {
'Name': '[Optional] Password for SMTP server if protected with '
'password',
'Description': 'Enter the password for the SMTP server if protected'
' with password. It is optional and can be '
'left empty if not protected with username and '
'password.',
'Type': 'string',
'Default': '',
'Encrypted': True,
},
'email_subject': {
'Name': '[Optional] Subject of the email notification',
'Description': 'Enter the subject for the email alert notification.'
'if this value is not provided the default value'
'will be used.',
'Type': 'string',
'Default': 'NAE detected a config change event'
},
'switch_host_name': {
'Name': '[Optional] Hostname for the switch to be used in '
'SMTP helo/ehlo message',
'Description': 'Enter a hostname for the switch to use in the SMTP'
' helo/ehlo message. If left blank, the hostname'
' of the switch along with the switch domain name',
'Type': 'string',
'Default': ''
}
}
Building the message
Secondly, we'll build the email. The logic here will check that all necessary values are specified, and will substitute in default values for optional arguments not specified. Note that there is error-checking built in here, such as with the SMTP server address.
Also part of this function is putting together the message body. The code here creates the email body such that it contains relevant information, including the IP address of the device whose configuration has changed, as well as a diff between the current configuration and the latest config checkpoint.
def create_email_notification(self, agent, mgmt_ip, config_diff,
host_name):
"""
Create and send an email alert with the configuration change details.
:param agent: Name of the agent generating the alert
:param mgmt_ip: Management VRF IP of the switch generating the alert.
:param config_diff: Difference in the configuration triggering
the alert.
:param host_name: Host name of the switch generating the alert.
"""
#prepare the arguments to be passed to ActionEmail
server_address = str(self.params['smtp_server_address'])
if server_address != "":
address = server_address.split(':')
if len(address) == 2:
server = address[0]
port = int(address[1])
else:
server = server_address
port = 25
else:
raise Exception("SMTP server address is not provided")
if str(self.params['recipient_email_address']) != "":
recipients = str(self.params['recipient_email_address'])
else:
raise Exception("Recipient email address not provided")
send_email = str(self.params['sender_email_address'])
if send_email != "":
sender = send_email
else:
sender = 'admin@' + host_name
if str(self.params['email_subject']) != "":
subject = str(self.params['email_subject']) + ' on device with' \
' IP: ' + mgmt_ip
else:
subject = "NAE detected a configuration change on device with " \
"IP:" + mgmt_ip
if str(self.params['smtp_server_user_id']):
username = str(self.params['smtp_server_user_id'])
else:
username = ""
if str(self.params['smtp_server_user_password']):
password = str(self.params['smtp_server_user_password'])
else:
password = ""
#prepare the email alert message body
agent_dashboard = self.nae_agent_uri(mgmt_ip, agent)
title = ('Configuration change detected in device with IP: %s. '
'\n\n\n\n'
'More details in %s. \n\n\n'
'Changes since last checkpoint:' %
(mgmt_ip, agent_dashboard))
email_body = title + escape(config_diff, False)
#Execute Action Email to send the email alert.
try:
ActionEmail(email_body, server=server, port=port, sender=sender,
recipients=recipients, subject=subject,
host_name=host_name,
username=username, password=password)
self.logger.info(
"Agent {} sent an email alert for configuration change"
"".format(agent))
except Exception as e:
self.logger.error(
"Error while trying to execute ActionEmail: {} for agent "
"{}".format(str(e), agent))
ActionCustomReport(str(e), title=Title("Error while trying to "
"execute ActionEmail"))
Creating the ActionEmail class
Finally, we create the class whose constructor handles connecting to the SMTP server and sending the email.
For example:
class ActionEmail:
def __init__(self, email_body, **kwargs):
"""
ActionEmail sends an email with the message passed as argument to it
as body of the email.
:param email_body: Content to be put in the alert email body.
:param params: NAE Script parameters to be used as replacement for {}
in the ActionEmail arguments.
:param kwargs: Other fields that are passed as keyword arguments to
the ActionEmail
The required arguments that are needed to pass keyword arguments are
as follows:
server : IP address or hostname of the SMTP server.
recipients: Comma separated list of email addresses to which the
email alert needs to be sent.
hostname: Hostname to be used in the SMTP helo/ehlo messages.
The following optional arguments that can be passed as keyword
arguments:
port: Port on which SMTP server listens. The default value of
25 is used if it's value is not passed.
content_type: Type of the content in the email. Default value
of 'plain' is used if it's value is not passed.
subject: Message to be sent as the subject of the email alert.
Default value is empty string.
username: SMTP server credential user name if the SMTP server
access is protected wih user name and password.
password: SMTP server credential password if the SMTP server
access is password protected.
"""
if 'server' in kwargs:
self.server = kwargs['server']
else:
raise Exception("SMTP server address not provided")
if 'recipients' in kwargs:
self.recipients = kwargs['recipients']
else:
raise Exception("Recipients email address not provided")
if 'host_name' in kwargs:
self.host_name = kwargs['host_name']
else:
raise Exception("Device host name not provided")
self.port = kwargs.get('port', 25)
self.sender = kwargs.get('sender', 'admin@' + self.host_name)
self.content_type = kwargs.get('content_type', 'plain')
self.subject = kwargs.get('subject', '')
msg = MIMEText(email_body, self.content_type)
msg['Subject'] = self.subject
msg['From'] = self.sender
msg['To'] = self.recipients
conn = SMTP(self.server, self.port)
if 'username' in kwargs and kwargs['username'] != "":
if 'password' in kwargs and kwargs['password'] != "":
conn.ehlo(self.host_name)
conn.starttls()
conn.login(kwargs['username'], kwargs['password'])
else:
conn.helo(self.host_name)
try:
conn.send_message(msg)
finally:
conn.quit()
And that's it!
Updated almost 2 years ago