Network to Code is releasing a new Nautobot app—a plugin to interact with Cisco Meraki using the existing Nautobot ChatOps framework! This app comes with prepackaged commands to gather data about your Meraki environment via chat commands. The Nautobot ChatOps app lowers the barrier of entry by providing interactions with chat platforms of Mattermost, Microsoft Teams, Slack, and Webex Teams. The amount of code needed to generate ChatOps commands is low, and the Meraki ChatOps app can be expanded to include new commands to fit any number of use cases.
The Nautobot ChatOps Meraki app extends the capabilities of the Nautobot ChatOps app to include a new chat command. This is done by registering to the Python entry point in Nautobot plugin ChatOps that provides functionality to the code written to interact with Meraki.
This app introduces the following subcommands to the meraki command:
get-organizations
get-admins
get-devices
get-networks
get-switchports
get-switchports-status
get-firewall-performance
get-wlan-ssids Query Meraki for all SSIDs for a given Network.
get-camera-recent Query Meraki Recent Camera Analytics.
get-clients Query Meraki for List of Clients.
get-neighbors Query Meraki for List of LLDP or CDP Neighbors.
configure-basic-access-port Configure an access port with description, VLAN, and state.
cycle-port Cycles a port on a given switch.
Get Organizations
Gather all the Meraki Organizations based on the API Key used during setup.
Get Admins
Based on an Organization Name, return the Meraki Admins.
Get Devices
Gathers devices from Meraki. Provides a device type option in order to limit scope.
Get Networks
Gathers names of networks from Meraki.
Get Switchports
Gathers switch ports configuration details from an MS(Meraki Switch Model) switch device.
Get Switchports Status
Gathers switch ports operating status from an MS(Meraki Switch Model) switch device.
Get Firewall Performance
Query Meraki with a firewall to device performance. This provides an integer value.
Get WLAN SSIDS
Query Meraki for all SSIDs for a given Network.
Get Camera Recent
Query Meraki Recent Camera Analytics.
Get Clients
Query Meraki for List of Clients.
Get Neighbors
Query Meraki for List of LLDP or CDP Neighbors based on a device.
Configure Basic Access Port
Configure an access port with description, VLAN, and state.
Cycle Port
Cycles a port on a given switch. Equivalent to a shutdown, no shutdown procedure.
Extending the App
Cisco Meraki is a cloud-managed infrastructure manager that includes multiple different products. Since Meraki can manage switches, security devices, cameras, and wireless, the initial plugin aims to provide some value in each of these product lines. Extending this plugin to include more commands is simple, and I encourage contributions back into this project.
Conclusion
This is just the start of what is possible in extending the Nautobot ChatOps ecosystem. Whether you want to write your own, or use one of the additional plugins that has been created by Network to Code, the ecosystem for ChatOps is going to continue to grow! Keep an eye out for additional ChatOps plugins to be announced here!
Does this all sound amazing? Want to know more about how Network to Code can help you do this, reach out to our sales team. If you want to help make this a reality for our clients, check out our careers page.
In the spirit of Network to Code’s continuing development in the ChatOps space, we are releasing a new Nautobot app. It is an application to interact with Arista CloudVision using the existing Nautobot ChatOps framework. This ChatOps integration comes pre-packaged with commands to gather various data about CloudVision (CV). You can now get key information from CV directly from chat!
This app can work with either an on-prem instance of CloudVision or CloudVision as-a-Service. For installation steps, refer to the app’s README. To install the underlying Nautobot ChatOps framework, refer to the documentation found here.
Looking at the image below gives a visual representation of how this app works with the core ChatOps app & plugin.
The Nautobot ChatOps CloudVision plugin extends the capabilities of the Nautobot ChatOps framework addding a new chat command. The new CloudVision plugin introduces the following commands:
get-devices-in-container
get-configlet
get-device-configuration
get-task-logs
get-applied-configlets
get-active-events
get-tags
get-device-cve
Get Devices in Container
The get-devices-in-container sub-command will prompt the user to choose a container from the existing containers in CloudVision. It will then give you a list of all devices in the chosen container.
Get Configlet
The get-configlet sub-command will query CloudVision for the currently defined configlets, ask you to choose one, and give you the contents of the chosen configlet.
Get Device Configuration
The get-device-configuration sub-command queries CloudVision for all of its devices, prompts you to choose one, and retrieves the specified device configuration.
Get Task Logs
The get-task-logs sub-command allows you to choose a task by Task ID. It will then give you the logs of that task.
Get Applied Configlets
The get-applied-configlets sub-command allows you to get a list of configlets applied to either a container or a device.
Get Active Events
The get-active-events sub-command allows you to get active events filtered by device, type, or severity within a given time frame. When the sub-command is executed, a prompt will ask you for the filter you wish to apply. From there it will ask you for a start time. We configured it so that you may specify a start time relative to the current time by using an h for hours, d for days, and w for weeks. For example, when prompted for a start time, you’d enter the value -2w if you wanted to go back 2 weeks from the current time. For 2 days, you’d type -2d. The last prompt asks you for an end time. You can again use the same syntax mentioned before but you may also type the word now to use the current time.
Get Tags
The get-tags sub-command will present a list of all the tags assigned to a specific device.
Get Device CVE
The get-device-cve sub-command gets a list of all CVE’s discovered by CloudVision for a specific device.
Conclusion
These commands only handle a subset of the information that can be gathered by a CloudVision chatbot. You can contribute more commands with minimal Python code! Because the Nautobot ChatOps plugin lowers the barrier of entry by already handling the interaction between Nautobot and chat applications like Mattermost, Microsoft Teams, Slack, and Webex, creating new commands is extremely easy. We encourage you to create your own commands by building on top of existing commands and plugins we at NTC have created, or to create your own command to interact with something you use on a daily basis. We’re going to continue creating new plugins for ChatOps, so keep an eye out for additional announcements here!
Does this all sound amazing? Want to know more about how Network to Code can help you do this, reach out to our sales team. If you want to help make this a reality for our clients, check out our careers page.
ChatOps and chat bots are becoming an ever more popular method to interact with network systems. Whether the command is to get operational status, to full-on operational configuration commands, interactions via chat is here. Nautobot not only is a Source of Truth, but is also a Network Automation Platform to build apps on top of! One app already released is the ChatOps plugin that you can use to accelerate the implementation of your individual chatbot needs! You can explore a public demo of the ChatOps plugin in the Network to Code (NTC) Slack channel #nautobot-chatops. The ChatOps plugin today has support for integration with Microsoft Teams, Cisco Webex, Slack, and Mattermost. To install and configure the plugin with your own particular chat environment, take a look at the docs.
Extending the ChatOps plugin to support your own commands is quite straightforward. This post provides a walk-through guide to getting up and started with your own custom chat commands. Underneath the entire plugin is Python, which allows your chat commands to interact with nearly any system you want. Want to get information from a third-party API and present it back? Want to kick off an Ansible playbook execution in AWX/Tower? Want to interact with a network device over SSH? All of these are absolutely possible!
Exploring ChatOps Connection to Nautobot
By default and out of the box, the Nautobot ChatOps plugin will provide the capability to query the Nautobot environment directly. This is what is enabled on the NTC Slack channel. It is tied to the demo instance of Nautobot. Take a look at our NFD talk introduction to ChatOps and demonstration for more examples of Nautobot ChatOps features available with installation.
Exploring Slack-Specific Commands
Slack Command Help
Within Slack specifically, to get started you probably want to see all of the commands that are available for the chatbot. In this case the bot name is nautobot, so when you send the command /nautobot to the channel you get the response with the following:
Some points to note as you start thinking about adding your own commands:
Ordering of the commands: This is controlled by the order of the functions as they get defined in the plugin definition file.
Help text: This is gathered from the first line of the docstring that accompanies the function.
Slack Command Example – Get Devices
First, looking at the help output for get-devices it shows /nautobot get-devices [filter-type] [filter-value]. If one were to issue the command with the filter-type and filter-value defined, then that is all that is needed to kick off the command. The second option is to just issue the command /nautobot get-devices and the bot will prompt back for those particular items. As the prompt gets answered, the next option continues on. So in this example you can get the data with either the command where you follow the prompts, or just issue the complete command /nautobot get-devices site nyc.
The result is a text entry that is:
Name Status Tenant Site Rack Role Type IP Address==================================================================================================nyc-bb-01.infra.ntc.com Active New York City Backbone vMX nyc-leaf-01.infra.ntc.com Active New York City leaf vEOS nyc-leaf-02.infra.ntc.com Active New York City leaf vEOS nyc-rtr-01.infra.ntc.com Active New York City Router vMX nyc-rtr-02.infra.ntc.com Active New York City Router vMX nyc-spine-01.infra.ntc.com Active New York City spine vEOS nyc-spine-02.infra.ntc.com Active New York City spine vEOS
Command Output Observations
Some things from the code here:
Site nyc is a slug, as in the imagery it shows the full name New York City but in the output shortcut that gets added it shows nyc. This matches the slug since spaces are not allowed in the section of the commands. Each space is a separator for the command to process.
Shortcut text is specified and written in the code had as part of the response for the bot. The bot itself does not add this or any other text.
Creating Your Own Chat Command
This walk-through will be to write a new chat command (as a Nautobot ChatOps plugin) that will be named netchat within Slack. The focus here is on getting started writing your own code rather than the chat platform itself. What gets outlined here should work for any other chat platform with minimal modifications. The document for chat setup referenced earlier is your guide to walk through getting the chat platform ready.
Once you have written the code, the same code is designed to work with Slack, Microsoft Teams, Cisco Webex, and Mattermost. Nautobot ChatOps can interact with multiple platforms from the same API endpoint. Allowing for interactions from any of the platforms defined in the Nautobot configuration.
There is not a limitation to only these four chat platforms. This can be expanded with additional dispatchers to be added into the ChatOps plugin. Recently this was extended to support Mattermost as an example, which was not supported at the beginning of 2021.
In this walk-through, we will be adding a command to get the device inventory from a Meraki Organization by interacting with the Meraki Dashboard API.
Demo Setup
Demo Setup Assumptions
Nautobot is locally installed via the local installation methods
The Nautobot ChatOps Plugin is required for adding custom chat commands
Demo Setup – Nautobot Configuration
The first step is to set up the Nautobot configuration. Within (/opt/nautobot/nautobot_config.py) a dictionary is added to PLUGINS_CONFIG. It shows as follows:
nautobot_chatops is the required first key to indicate this is the plugin configuration for the ChatOps plugin.
The value of nautobot_chatops is another dictionary that has the keys:
enable_slack: Boolean field for having Slack enabled. There are enable_* values for each of the chat platforms there are dispatchers for. There can be multiple platforms enabled at one time.
slack_api_token: Token for the bot defined within the chatbot config on api.slack.com
slack_signing_secret: Signing secret as defined within the chatbot config on api.slack.com
There are other keys per platform, depending on the chat platform
Demo Setup – Nautobot Environment Setup
The Slack configuration is configured in the environment, not in the configuration file. The environment is read by the configuration file and thus loaded into Nautobot. In order to get the updated environment, the Nautobot service files are updated to reference the environment file /opt/nautobot.env.
Add EnvironmentFile=/opt/nautobot/.env to both /etc/systemd/system/nautobot.service and /etc/systemd/system/nautobot-worker.service files.
After modifying the systemd files, execute daemon-reload and restart the services. Once the service is restarted it is recommended to check the status of the bot by issuing a Slack command /nautobot to get the help context.
Inside the environment file is the Meraki API key to put the API key into the environment as required by the Meraki SDK.
Using Existing Methods for Portability
The first recommendation is to look at the design docs that show how the plugin is designed. It is recommended, wherever possible, to use the Python methods provided, especially in the interaction back to the chat platform. For example, one could set up the mention of @username easily in the response to tag a user. However, there is a Python method within the dispatcher to get the user mention. This way, should a platform need to be migrated say from Slack to Microsoft Teams, updates are not needed to the code, just a change of the settings. This allows for the chat bot to interact with multiple chat platforms at the same time. Take a look at the code inside of GitHub for your specific platform to see what methods are available!
Creating the Custom Chat Commands
After setting up the settings mentioned above to load the configuration into the environment, I logged into the user account for nautobot with sudo -iu nautobot. Following the instructions for Nautobot v1.0.0b2 or later, this has the user root in /opt/nautobot. Here create a new directory plugins/netchat (/opt/nautobot/plugins/netchat/).
The directory structure that will be built out is:
First step in this is to build out the directory structure and adding the __init__.py file. This creates a new /opt/nautobot/plugins directory, as well as the directory structure for the package netchat.
cd /opt/nautobotmkdir -p plugins/netchat/netchattouch /opt/nautobot/plugins/netchat/netchat/__init__.py
This ChatOps plugin will use Python Poetry to handle the packaging and configuration. To install Poetry, take a look at the installation steps outlined by Poetry. This should follow their installation methods, and do not install with Python PIP. They were specifically chosen to help with the entry point configuration which is required to add onto the chatops plugin. The configuration pieces specific to the netchat plugin for the /opt/nautobot/plugins/netchat/pyproject.toml:
[tool.poetry]name ="netchat"version ="0.1.1"description =""authors = ["Network to Code <opensource@networktocode.com>"][tool.poetry.plugins."nautobot.workers"]"netchat"="netchat.worker:netchat"
The first section of tool.poetry outlines the Python package itself, in this instance it is called netchat. The second section tool.poetry.plugins."nautobot.workers" defines the “entry point” to register the code as an extension of the ChatOps plugin.
The left-hand side of "netchat" = corresponds to the slash command that is being installed, and the right-hand side of the line = "netchat.worker:netchat is how to get to the function. In this case, netchat.worker refers to the file netchat/worker.py, and the netchat to the right of the : is the function name inside of this file.
In the netchat plugin, the code for the chat bot will be housed within /opt/nautobot/plugins/netchat/worker.py. This is from the reference in the pyproject.toml file in the configuration "netchat" = "netchat.worker:netchat". This could be any file name, something that meaningful to the plugin setup. The code for worker.py is:
"""Demo netchat addition to Nautobot."""import loggingfrom django_rq import jobfrom nautobot_chatops.workers import subcommand_of, handle_subcommandsfrom nautobot_chatops.choices import CommandStatusChoicesimport merakilogger = logging.getLogger("rq.worker")@job("default")def netchat(subcommand,**kwargs):"""Interact with netchat.""" return handle_subcommands("netchat", subcommand,**kwargs)def get_meraki_orgs():"""Query the Meraki Dashboard API for a list of defined organizations.""" dashboard = meraki.DashboardAPI(suppress_logging=True) return dashboard.organizations.getOrganizations()def meraki_devices(org_name):"""Query the Meraki Dashboard API for a list of devices in the given organization.""" # Get the org ID from the Get Meraki Orgs org_list =get_meraki_orgs() dashboard = meraki.DashboardAPI(suppress_logging=True) for org inorg_list:if org["name"] ==org_name: device_list = dashboard.organizations.getOrganizationDevices(organizationId=org["id"])return device_listreturn []@subcommand_of("netchat")def get_meraki_devices(dispatcher, org_name=None):"""Gathers devices from Meraki API endpoint.""" logger.info(f"ORG NAME: {org_name}")if not org_name: # The user didn't specify an organization, so prompt them to pick one org_list =get_meraki_orgs() # Build the list of sites, each asapairof (user-visiblestring,internalvalue) entries choices = [(x["name"], x["name"]) for x in org_list] dispatcher.prompt_from_menu(f"netchat get-meraki-devices","Select Organization", choices) # Returning False indicates that the command needed to prompt the user for more information return False # If gathering information from another system may take some time, it's useful to send the user dispatcher.send_markdown( f"Stand by {dispatcher.user_mention()}, I'm getting the devices at the Organization {org_name}!" ) devices =meraki_devices(org_name) # Render the list of devices to Markdown for display to the user's chat client blocks = [ dispatcher.markdown_block(f"{dispatcher.user_mention()} here are the devices at {org_name}"), dispatcher.markdown_block("\n".join([x["name"] for x in devices])), ] dispatcher.send_blocks(blocks)return CommandStatusChoices.STATUS_SUCCEEDED
The important parts are, first, the function registration of the chat command:
@job("default")def netchat(subcommand,**kwargs):"""Interact with netchat."""returnhandle_subcommands("netchat", subcommand,**kwargs)
This registers the netchat slash command to the ChatOps plugin. It corresponds with the entry point registration. Note the docstring of the function is what will be displayed to the chat user when listing available commands.
The chat command itself is then handled by the next defined function get_meraki_devices. This function registers itself to be a subcommand of netchat The first argument must always be dispatcher, which is an object used for all interactions with the chat platform. The remaining arguments are potential user inputs to the chat command; here we have just one, the org_name argument. This is the part of the chat command `/netchat get-meraki-devices `. When a user first sends the command `/netchat get-meraki-devices`, the org_name is `None`, which allows for the function to gather a list of choices and present it back.
@subcommand_of("netchat")def get_meraki_devices(dispatcher, org_name=None):"""Gathers devices from Meraki API endpoint."""if not org_name:<gatherorganizations> # When org_name is passed in<domorewithcode> ... # More Code
Through the prompts, the chat applications will not sort the data. In the example, everything is alphabetized because the code called for it to be alphabetized. Slack itself does not alphabetize the options. The text boxes are something that you can type in to filter for yourself.
Installation via Poetry
The final step after writing the code is that the package must be installed into the Nautobot environment. In this case since the package has not been published to PyPI, we will use Poetry to install it directly from source into the venv. This does require the virtual environment to be activated. As the Nautobot user:
cd ~source bin/activate
Once activated, move to the plugin directory, use Poetry to add requirements (in this case typing-extensions and meraki), then install the local package to the virtual environment.
Once the netchat package is installed, exit out of the Nautobot user. Then restart the Nautobot application and Nautobot worker process. If there are access grants that are restricting access to the chatbot, be sure to make the necessary updates in Nautobot to allow the new slash command.
sudo systemctl restart nautobot nautobot-worker
With the workers restarted, the slash command should be available on the chat application!
Conclusion
The ChatOps plugin is an excellent starting point for your own custom chat application. As demonstrated by its built-in commands, you can write chat commands that interact directly with Nautobot. But the ChatOps plugin can do far more than that. With Python, the capabilities to interact with other third-party services are endless!
Does this all sound amazing? Want to know more about how Network to Code can help you do this, reach out to our sales team. If you want to help make this a reality for our clients, check out our careers page.
We use cookies on our website to give you the most relevant experience by remembering your preferences and repeat visits. By clicking “Accept”, you consent to the use of ALL the cookies. In case of sale of your personal information, you may opt out by using the link Do not sell my personal information. Privacy | Cookies
This website uses cookies to improve your experience while you navigate through the website. Out of these cookies, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may have an effect on your browsing experience.
Necessary cookies are absolutely essential for the website to function properly. These cookies ensure basic functionalities and security features of the website, anonymously.
Cookie
Duration
Description
__hssc
30 minutes
HubSpot sets this cookie to keep track of sessions and to determine if HubSpot should increment the session number and timestamps in the __hstc cookie.
__hssrc
session
This cookie is set by Hubspot whenever it changes the session cookie. The __hssrc cookie set to 1 indicates that the user has restarted the browser, and if the cookie does not exist, it is assumed to be a new session.
cookielawinfo-checkbox-advertisement
1 year
Set by the GDPR Cookie Consent plugin, this cookie records the user consent for the cookies in the "Advertisement" category.
cookielawinfo-checkbox-analytics
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Analytics".
cookielawinfo-checkbox-functional
11 months
The cookie is set by GDPR cookie consent to record the user consent for the cookies in the category "Functional".
cookielawinfo-checkbox-necessary
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Necessary".
cookielawinfo-checkbox-others
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Other.
cookielawinfo-checkbox-performance
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Performance".
CookieLawInfoConsent
1 year
CookieYes sets this cookie to record the default button state of the corresponding category and the status of CCPA. It works only in coordination with the primary cookie.
viewed_cookie_policy
11 months
The cookie is set by the GDPR Cookie Consent plugin and is used to store whether or not user has consented to the use of cookies. It does not store any personal data.
Functional cookies help to perform certain functionalities like sharing the content of the website on social media platforms, collect feedbacks, and other third-party features.
Cookie
Duration
Description
__cf_bm
30 minutes
Cloudflare set the cookie to support Cloudflare Bot Management.
li_gc
5 months 27 days
Linkedin set this cookie for storing visitor's consent regarding using cookies for non-essential purposes.
lidc
1 day
LinkedIn sets the lidc cookie to facilitate data center selection.
UserMatchHistory
1 month
LinkedIn sets this cookie for LinkedIn Ads ID syncing.
Performance cookies are used to understand and analyze the key performance indexes of the website which helps in delivering a better user experience for the visitors.
Analytical cookies are used to understand how visitors interact with the website. These cookies help provide information on metrics the number of visitors, bounce rate, traffic source, etc.
Cookie
Duration
Description
__hstc
5 months 27 days
Hubspot set this main cookie for tracking visitors. It contains the domain, initial timestamp (first visit), last timestamp (last visit), current timestamp (this visit), and session number (increments for each subsequent session).
_ga
1 year 1 month 4 days
Google Analytics sets this cookie to calculate visitor, session and campaign data and track site usage for the site's analytics report. The cookie stores information anonymously and assigns a randomly generated number to recognise unique visitors.
_gat_gtag_UA_*
1 minute
Google Analytics sets this cookie to store a unique user ID.
_gid
1 day
Google Analytics sets this cookie to store information on how visitors use a website while also creating an analytics report of the website's performance. Some of the collected data includes the number of visitors, their source, and the pages they visit anonymously.
AnalyticsSyncHistory
1 month
Linkedin set this cookie to store information about the time a sync took place with the lms_analytics cookie.
CONSENT
2 years
YouTube sets this cookie via embedded YouTube videos and registers anonymous statistical data.
hubspotutk
5 months 27 days
HubSpot sets this cookie to keep track of the visitors to the website. This cookie is passed to HubSpot on form submission and used when deduplicating contacts.
ln_or
1 day
Linkedin sets this cookie to registers statistical data on users' behaviour on the website for internal analytics.
Advertisement cookies are used to provide visitors with relevant ads and marketing campaigns. These cookies track visitors across websites and collect information to provide customized ads.
Cookie
Duration
Description
bcookie
1 year
LinkedIn sets this cookie from LinkedIn share buttons and ad tags to recognize browser IDs.
bscookie
1 year
LinkedIn sets this cookie to store performed actions on the website.
li_sugr
3 months
LinkedIn sets this cookie to collect user behaviour data to optimise the website and make advertisements on the website more relevant.
VISITOR_INFO1_LIVE
5 months 27 days
YouTube sets this cookie to measure bandwidth, determining whether the user gets the new or old player interface.
YSC
session
Youtube sets this cookie to track the views of embedded videos on Youtube pages.
yt-remote-connected-devices
never
YouTube sets this cookie to store the user's video preferences using embedded YouTube videos.
yt-remote-device-id
never
YouTube sets this cookie to store the user's video preferences using embedded YouTube videos.
yt.innertube::nextId
never
YouTube sets this cookie to register a unique ID to store data on what videos from YouTube the user has seen.
yt.innertube::requests
never
YouTube sets this cookie to register a unique ID to store data on what videos from YouTube the user has seen.