As I wrote in this post, one of my goals for this year is to be able to compltely automate the build of my lab environment programatically.
In the last couple of jinja posts, I wrote about the basics of Jinja2 tempaltes and how they can be applied to building network configurations.
In this post, I'm going to take the next step and move those files from my local hard drive out to...
duh duh dahhhhhhhhhh
The cloud.
We're going to go over some basics on the tools we're using to make sure everyone's on the same page. cool?
Git is a widely-used source code management system for software development. It is a distributed revision control system with an emphasis on speed, data integrity, and support for distributed, non-linear workflows. wikipedia
GIT is a piece of software that allows you to track changes to files over time.
"Where software is built Powerful collaboration, code review, and code management for open source and private projects. Public projects are always free. " Github.com
GITHub is like facebook for developers. It's a place where you can sync your local GIT repository to a central location, and then sync that central location to other local repositories.
A repository is essentially a collection of files that make up a project. You could think of it like a folder or directory. That analogy is not exact as it's possible for a repository to have multiple sub-folders or directories, but it's close enough for our purposes.
GIT was definitely designed for software developers to as a versioning control system while developing software, but you can use it for tracking changes to things other than
You could use it for anything text format that you want to track changes to over time. For example
There are a lot of interesting uses for GIT, one of those that we're going to use today is looking at storing our Jinja2 templates on a public GIT repository and loading them directly into our python script as part of the code.
Unles you've already got them, you'll need to pip install jinj2
and pip install requests
these two libraries before loading them into your running environment.
import requests
import yaml
import githubuser
from jinja2 import Environment, FileSystemLoader, Template
Like with most things in python, if it's useful enough, chances are there's probably someone else who already put a library together for that. In our case, we're going to use the python request library to handle loading files directly from our Github repository.
The first thing we'll do is load the HPE comware switch template from that we used in this post. If you wanted to take a look at this directly on github, it can be found here. All we have to do is to copy and paste the URL from our browser directly into the first input of the requests.get function.
note: The requests function will return a whole object that has various attributes. the " .text " at the end of this tells the function to just give us the contents of the file, not of the other information, like the HTTP status_code.
Simple, right?
comware_template = requests.get('https://github.com/netmanchris/Jinja2-Network-Configurations-Scripts/blob/master/simple_comware.j2').text
So now that we've loaded the contents of the simple_comware.j2 template directly from the Github site into the comware_template variable. Let's take a look to make sure that we have what we need.
print (comware_template)
<!DOCTYPE html> <html lang="en" class=""> <head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# object: http://ogp.me/ns/object# article: http://ogp.me/ns/article# profile: http://ogp.me/ns/profile#"> <meta charset='utf-8'> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="Content-Language" content="en"> <meta name="viewport" content="width=1020"> <title>Jinja2-Network-Configurations-Scripts/simple_comware.j2 at master · netmanchris/Jinja2-Network-Configurations-Scripts · GitHub</title> <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub"> <link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub"> <link rel="apple-touch-icon" href="/apple-touch-icon.png"> <link rel="apple-touch-icon" sizes="57x57" href="/apple-touch-icon-57x57.png"> <link rel="apple-touch-icon" sizes="60x60" href="/apple-touch-icon-60x60.png"> <link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-72x72.png"> <link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon-76x76.png"> <link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114x114.png"> <link rel="apple-touch-icon" sizes="120x120" href="/apple-touch-icon-120x120.png"> <link rel="apple-touch-icon" sizes="144x144" href="/apple-touch-icon-144x144.png"> <link rel="apple-touch-icon" sizes="152x152" href="/apple-touch-icon-152x152.png"> <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png"> <meta property="fb:app_id" content="1401488693436528"> <meta content="@github" name="twitter:site" /><meta content="summary" name="twitter:card" /><meta content="netmanchris/Jinja2-Network-Configurations-Scripts" name="twitter:title" /><meta content="Jinja2-Network-Configurations-Scripts - Network Configuration Scripts" name="twitter:description" /><meta content="https://avatars1.githubusercontent.com/u/9815146?v=3&s=400" name="twitter:image:src" /> <meta content="GitHub" property="og:site_name" /><meta content="object" property="og:type" /><meta content="https://avatars1.githubusercontent.com/u/9815146?v=3&s=400" property="og:image" /><meta content="netmanchris/Jinja2-Network-Configurations-Scripts" property="og:title" /><meta content="https://github.com/netmanchris/Jinja2-Network-Configurations-Scripts" property="og:url" /><meta content="Jinja2-Network-Configurations-Scripts - Network Configuration Scripts" property="og:description" /> <meta name="browser-stats-url" content="https://api.github.com/_private/browser/stats"> <meta name="browser-errors-url" content="https://api.github.com/_private/browser/errors"> <link rel="assets" href="https://assets-cdn.github.com/"> <meta name="pjax-timeout" content="1000"> <meta name="msapplication-TileImage" content="/windows-tile.png"> <meta name="msapplication-TileColor" content="#ffffff"> <meta name="selected-link" value="repo_source" data-pjax-transient> <meta name="google-site-verification" content="KT5gs8h0wvaagLKAVWq8bbeNwnZZK1r1XQysX3xurLU"> <meta name="google-analytics" content="UA-3769691-2"> <meta content="collector.githubapp.com" name="octolytics-host" /><meta content="github" name="octolytics-app-id" /><meta content="60148A1A:0600:25A84BB:56A3D8E2" name="octolytics-dimension-request_id" /> <meta content="/<user-name>/<repo-name>/blob/show" data-pjax-transient="true" name="analytics-location" /> <meta class="js-ga-set" name="dimension1" content="Logged Out"> <meta name="hostname" content="github.com"> <meta name="user-login" content=""> <meta name="expected-hostname" content="github.com"> <link rel="mask-icon" href="https://assets-cdn.github.com/pinned-octocat.svg" color="#4078c0"> <link rel="icon" type="image/x-icon" href="https://assets-cdn.github.com/favicon.ico"> <meta content="0eeeaba99e18a2a857407008b071f2f698c9b4bd" name="form-nonce" /> <link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/github-fefb561e0a804c2a181aed0adbaa8ba5aa475e09b7692a3f737cb8bb50ef1c27.css" media="all" rel="stylesheet" /> <link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/github2-b2d8d1fd984ff1b181275aaa1276c82bb266b4f58f08f3075941d786d5b432ec.css" media="all" rel="stylesheet" /> <meta http-equiv="x-pjax-version" content="f08e6513a91b7d33dce8dbaaa01f9efd"> <meta name="description" content="Jinja2-Network-Configurations-Scripts - Network Configuration Scripts"> <meta name="go-import" content="github.com/netmanchris/Jinja2-Network-Configurations-Scripts git https://github.com/netmanchris/Jinja2-Network-Configurations-Scripts.git"> <meta content="9815146" name="octolytics-dimension-user_id" /><meta content="netmanchris" name="octolytics-dimension-user_login" /><meta content="39023270" name="octolytics-dimension-repository_id" /><meta content="netmanchris/Jinja2-Network-Configurations-Scripts" name="octolytics-dimension-repository_nwo" /><meta content="true" name="octolytics-dimension-repository_public" /><meta content="false" name="octolytics-dimension-repository_is_fork" /><meta content="39023270" name="octolytics-dimension-repository_network_root_id" /><meta content="netmanchris/Jinja2-Network-Configurations-Scripts" name="octolytics-dimension-repository_network_root_nwo" /> <link href="https://github.com/netmanchris/Jinja2-Network-Configurations-Scripts/commits/master.atom" rel="alternate" title="Recent Commits to Jinja2-Network-Configurations-Scripts:master" type="application/atom+xml"> <link rel="canonical" href="https://github.com/netmanchris/Jinja2-Network-Configurations-Scripts/blob/master/simple_comware.j2" data-pjax-transient> </head> <body class="logged_out env-production vis-public page-blob"> <a href="#start-of-content" tabindex="1" class="accessibility-aid js-skip-to-content">Skip to content</a> <div class="header header-logged-out" role="banner"> <div class="container clearfix"> <a class="header-logo-wordmark" href="https://github.com/" data-ga-click="(Logged out) Header, go to homepage, icon:logo-wordmark"> <span aria-hidden="true" class="mega-octicon octicon-logo-github"></span> </a> <div class="header-actions" role="navigation"> <a class="btn btn-primary" href="/join?source=header" data-ga-click="(Logged out) Header, clicked Sign up, text:sign-up">Sign up</a> <a class="btn" href="/login?return_to=%2Fnetmanchris%2FJinja2-Network-Configurations-Scripts%2Fblob%2Fmaster%2Fsimple_comware.j2" data-ga-click="(Logged out) Header, clicked Sign in, text:sign-in">Sign in</a> </div> <div class="site-search repo-scope js-site-search" role="search"> <!-- </textarea> --><!-- '"` --><form accept-charset="UTF-8" action="/netmanchris/Jinja2-Network-Configurations-Scripts/search" class="js-site-search-form" data-global-search-url="/search" data-repo-search-url="/netmanchris/Jinja2-Network-Configurations-Scripts/search" method="get"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /></div> <label class="js-chromeless-input-container form-control"> <div class="scope-badge">This repository</div> <input type="text" class="js-site-search-focus js-site-search-field is-clearable chromeless-input" data-hotkey="s" name="q" placeholder="Search" aria-label="Search this repository" data-global-scope-placeholder="Search GitHub" data-repo-scope-placeholder="Search" tabindex="1" autocapitalize="off"> </label> </form> </div> <ul class="header-nav left" role="navigation"> <li class="header-nav-item"> <a class="header-nav-link" href="/explore" data-ga-click="(Logged out) Header, go to explore, text:explore">Explore</a> </li> <li class="header-nav-item"> <a class="header-nav-link" href="/features" data-ga-click="(Logged out) Header, go to features, text:features">Features</a> </li> <li class="header-nav-item"> <a class="header-nav-link" href="https://enterprise.github.com/" data-ga-click="(Logged out) Header, go to enterprise, text:enterprise">Enterprise</a> </li> <li class="header-nav-item"> <a class="header-nav-link" href="/pricing" data-ga-click="(Logged out) Header, go to pricing, text:pricing">Pricing</a> </li> </ul> </div> </div> <div id="start-of-content" class="accessibility-aid"></div> <div id="js-flash-container"> </div> <div role="main" class="main-content"> <div itemscope itemtype="http://schema.org/WebPage"> <div id="js-repo-pjax-container" class="context-loader-container js-repo-nav-next" data-pjax-container> <div class="pagehead repohead instapaper_ignore readability-menu experiment-repo-nav"> <div class="container repohead-details-container"> <ul class="pagehead-actions"> <li> <a href="/login?return_to=%2Fnetmanchris%2FJinja2-Network-Configurations-Scripts" class="btn btn-sm btn-with-count tooltipped tooltipped-n" aria-label="You must be signed in to watch a repository" rel="nofollow"> <span aria-hidden="true" class="octicon octicon-eye"></span> Watch </a> <a class="social-count" href="/netmanchris/Jinja2-Network-Configurations-Scripts/watchers"> 3 </a> </li> <li> <a href="/login?return_to=%2Fnetmanchris%2FJinja2-Network-Configurations-Scripts" class="btn btn-sm btn-with-count tooltipped tooltipped-n" aria-label="You must be signed in to star a repository" rel="nofollow"> <span aria-hidden="true" class="octicon octicon-star"></span> Star </a> <a class="social-count js-social-count" href="/netmanchris/Jinja2-Network-Configurations-Scripts/stargazers"> 0 </a> </li> <li> <a href="/login?return_to=%2Fnetmanchris%2FJinja2-Network-Configurations-Scripts" class="btn btn-sm btn-with-count tooltipped tooltipped-n" aria-label="You must be signed in to fork a repository" rel="nofollow"> <span aria-hidden="true" class="octicon octicon-repo-forked"></span> Fork </a> <a href="/netmanchris/Jinja2-Network-Configurations-Scripts/network" class="social-count"> 0 </a> </li> </ul> <h1 itemscope itemtype="http://data-vocabulary.org/Breadcrumb" class="entry-title public "> <span aria-hidden="true" class="octicon octicon-repo"></span> <span class="author"><a href="/netmanchris" class="url fn" itemprop="url" rel="author"><span itemprop="title">netmanchris</span></a></span><!-- --><span class="path-divider">/</span><!-- --><strong><a href="/netmanchris/Jinja2-Network-Configurations-Scripts" data-pjax="#js-repo-pjax-container">Jinja2-Network-Configurations-Scripts</a></strong> <span class="page-context-loader"> <img alt="" height="16" src="https://assets-cdn.github.com/images/spinners/octocat-spinner-32.gif" width="16" /> </span> </h1> </div> <div class="container"> <nav class="reponav js-repo-nav js-sidenav-container-pjax js-octicon-loaders" role="navigation" data-pjax="#js-repo-pjax-container"> <a href="/netmanchris/Jinja2-Network-Configurations-Scripts" aria-label="Code" aria-selected="true" class="js-selected-navigation-item selected reponav-item" data-hotkey="g c" data-selected-links="repo_source repo_downloads repo_commits repo_releases repo_tags repo_branches /netmanchris/Jinja2-Network-Configurations-Scripts"> <span aria-hidden="true" class="octicon octicon-code"></span> Code </a> <a href="/netmanchris/Jinja2-Network-Configurations-Scripts/issues" class="js-selected-navigation-item reponav-item" data-hotkey="g i" data-selected-links="repo_issues repo_labels repo_milestones /netmanchris/Jinja2-Network-Configurations-Scripts/issues"> <span aria-hidden="true" class="octicon octicon-issue-opened"></span> Issues <span class="counter">0</span> </a> <a href="/netmanchris/Jinja2-Network-Configurations-Scripts/pulls" class="js-selected-navigation-item reponav-item" data-hotkey="g p" data-selected-links="repo_pulls /netmanchris/Jinja2-Network-Configurations-Scripts/pulls"> <span aria-hidden="true" class="octicon octicon-git-pull-request"></span> Pull requests <span class="counter">0</span> </a> <a href="/netmanchris/Jinja2-Network-Configurations-Scripts/pulse" class="js-selected-navigation-item reponav-item" data-selected-links="pulse /netmanchris/Jinja2-Network-Configurations-Scripts/pulse"> <span aria-hidden="true" class="octicon octicon-pulse"></span> Pulse </a> <a href="/netmanchris/Jinja2-Network-Configurations-Scripts/graphs" class="js-selected-navigation-item reponav-item" data-selected-links="repo_graphs repo_contributors /netmanchris/Jinja2-Network-Configurations-Scripts/graphs"> <span aria-hidden="true" class="octicon octicon-graph"></span> Graphs </a> </nav> </div> </div> <div class="container new-discussion-timeline experiment-repo-nav"> <div class="repository-content"> <a href="/netmanchris/Jinja2-Network-Configurations-Scripts/blob/ff92fa74e6c72c633a4e93ed204a9a6bc56d11f6/simple_comware.j2" class="hidden js-permalink-shortcut" data-hotkey="y">Permalink</a> <!-- blob contrib key: blob_contributors:v21:d75b7c9a36c8f97125dd1a803c96b7bb --> <div class="file-navigation js-zeroclipboard-container"> <div class="select-menu js-menu-container js-select-menu left"> <button class="btn btn-sm select-menu-button js-menu-target css-truncate" data-hotkey="w" title="master" type="button" aria-label="Switch branches or tags" tabindex="0" aria-haspopup="true"> <i>Branch:</i> <span class="js-select-button css-truncate-target">master</span> </button> <div class="select-menu-modal-holder js-menu-content js-navigation-container" data-pjax aria-hidden="true"> <div class="select-menu-modal"> <div class="select-menu-header"> <span aria-label="Close" class="octicon octicon-x js-menu-close" role="button"></span> <span class="select-menu-title">Switch branches/tags</span> </div> <div class="select-menu-filters"> <div class="select-menu-text-filter"> <input type="text" aria-label="Filter branches/tags" id="context-commitish-filter-field" class="js-filterable-field js-navigation-enable" placeholder="Filter branches/tags"> </div> <div class="select-menu-tabs"> <ul> <li class="select-menu-tab"> <a href="#" data-tab-filter="branches" data-filter-placeholder="Filter branches/tags" class="js-select-menu-tab" role="tab">Branches</a> </li> <li class="select-menu-tab"> <a href="#" data-tab-filter="tags" data-filter-placeholder="Find a tag…" class="js-select-menu-tab" role="tab">Tags</a> </li> </ul> </div> </div> <div class="select-menu-list select-menu-tab-bucket js-select-menu-tab-bucket" data-tab-filter="branches" role="menu"> <div data-filterable-for="context-commitish-filter-field" data-filterable-type="substring"> <a class="select-menu-item js-navigation-item js-navigation-open selected" href="/netmanchris/Jinja2-Network-Configurations-Scripts/blob/master/simple_comware.j2" data-name="master" data-skip-pjax="true" rel="nofollow"> <span aria-hidden="true" class="octicon octicon-check select-menu-item-icon"></span> <span class="select-menu-item-text css-truncate-target" title="master"> master </span> </a> </div> <div class="select-menu-no-results">Nothing to show</div> </div> <div class="select-menu-list select-menu-tab-bucket js-select-menu-tab-bucket" data-tab-filter="tags"> <div data-filterable-for="context-commitish-filter-field" data-filterable-type="substring"> </div> <div class="select-menu-no-results">Nothing to show</div> </div> </div> </div> </div> <div class="btn-group right"> <a href="/netmanchris/Jinja2-Network-Configurations-Scripts/find/master" class="js-show-file-finder btn btn-sm" data-pjax data-hotkey="t"> Find file </a> <button aria-label="Copy file path to clipboard" class="js-zeroclipboard btn btn-sm zeroclipboard-button tooltipped tooltipped-s" data-copied-hint="Copied!" type="button">Copy path</button> </div> <div class="breadcrumb js-zeroclipboard-target"> <span class="repo-root js-repo-root"><span itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb"><a href="/netmanchris/Jinja2-Network-Configurations-Scripts" class="" data-branch="master" data-pjax="true" itemscope="url"><span itemprop="title">Jinja2-Network-Configurations-Scripts</span></a></span></span><span class="separator">/</span><strong class="final-path">simple_comware.j2</strong> </div> </div> <div class="commit-tease"> <span class="right"> <a class="commit-tease-sha" href="/netmanchris/Jinja2-Network-Configurations-Scripts/commit/ff92fa74e6c72c633a4e93ed204a9a6bc56d11f6" data-pjax> ff92fa7 </a> <time datetime="2016-01-23T17:55:36Z" is="relative-time">Jan 23, 2016</time> </span> <div> <img alt="@netmanchris" class="avatar" height="20" src="https://avatars1.githubusercontent.com/u/9815146?v=3&s=40" width="20" /> <a href="/netmanchris" class="user-mention" rel="author">netmanchris</a> <a href="/netmanchris/Jinja2-Network-Configurations-Scripts/commit/ff92fa74e6c72c633a4e93ed204a9a6bc56d11f6" class="message" data-pjax="true" title="Fixing GIT">Fixing GIT</a> </div> <div class="commit-tease-contributors"> <a class="muted-link contributors-toggle" href="#blob_contributors_box" rel="facebox"> <strong>1</strong> contributor </a> </div> <div id="blob_contributors_box" style="display:none"> <h2 class="facebox-header" data-facebox-id="facebox-header">Users who have contributed to this file</h2> <ul class="facebox-user-list" data-facebox-id="facebox-description"> <li class="facebox-user-list-item"> <img alt="@netmanchris" height="24" src="https://avatars3.githubusercontent.com/u/9815146?v=3&s=48" width="24" /> <a href="/netmanchris">netmanchris</a> </li> </ul> </div> </div> <div class="file"> <div class="file-header"> <div class="file-actions"> <div class="btn-group"> <a href="/netmanchris/Jinja2-Network-Configurations-Scripts/raw/master/simple_comware.j2" class="btn btn-sm " id="raw-url">Raw</a> <a href="/netmanchris/Jinja2-Network-Configurations-Scripts/blame/master/simple_comware.j2" class="btn btn-sm js-update-url-with-hash">Blame</a> <a href="/netmanchris/Jinja2-Network-Configurations-Scripts/commits/master/simple_comware.j2" class="btn btn-sm " rel="nofollow">History</a> </div> <button type="button" class="btn-octicon disabled tooltipped tooltipped-nw" aria-label="You must be signed in to make or propose changes"> <span aria-hidden="true" class="octicon octicon-pencil"></span> </button> <button type="button" class="btn-octicon btn-octicon-danger disabled tooltipped tooltipped-nw" aria-label="You must be signed in to make or propose changes"> <span aria-hidden="true" class="octicon octicon-trashcan"></span> </button> </div> <div class="file-info"> 14 lines (14 sloc) <span class="file-info-divider"></span> 497 Bytes </div> </div> <div class="blob-wrapper data type-text"> <table class="highlight tab-size js-file-line-container" data-tab-size="8"> <tr> <td id="L1" class="blob-num js-line-number" data-line-number="1"></td> <td id="LC1" class="blob-code blob-code-inner js-file-line">#sysname config</td> </tr> <tr> <td id="L2" class="blob-num js-line-number" data-line-number="2"></td> <td id="LC2" class="blob-code blob-code-inner js-file-line">sysname {{ simple['hostname'] }}</td> </tr> <tr> <td id="L3" class="blob-num js-line-number" data-line-number="3"></td> <td id="LC3" class="blob-code blob-code-inner js-file-line">#vlan config</td> </tr> <tr> <td id="L4" class="blob-num js-line-number" data-line-number="4"></td> <td id="LC4" class="blob-code blob-code-inner js-file-line">{% for vlan in simple['vlans'] -%}</td> </tr> <tr> <td id="L5" class="blob-num js-line-number" data-line-number="5"></td> <td id="LC5" class="blob-code blob-code-inner js-file-line">vlan {{ vlan['id'] }}</td> </tr> <tr> <td id="L6" class="blob-num js-line-number" data-line-number="6"></td> <td id="LC6" class="blob-code blob-code-inner js-file-line"> name {{ vlan['name'] }}</td> </tr> <tr> <td id="L7" class="blob-num js-line-number" data-line-number="7"></td> <td id="LC7" class="blob-code blob-code-inner js-file-line"> description {{ vlan['description'] }}</td> </tr> <tr> <td id="L8" class="blob-num js-line-number" data-line-number="8"></td> <td id="LC8" class="blob-code blob-code-inner js-file-line">{% endfor %}#snmp_config</td> </tr> <tr> <td id="L9" class="blob-num js-line-number" data-line-number="9"></td> <td id="LC9" class="blob-code blob-code-inner js-file-line">snmp-agent</td> </tr> <tr> <td id="L10" class="blob-num js-line-number" data-line-number="10"></td> <td id="LC10" class="blob-code blob-code-inner js-file-line">snmp-agent community read {{ simple['snmp']['read'] }}</td> </tr> <tr> <td id="L11" class="blob-num js-line-number" data-line-number="11"></td> <td id="LC11" class="blob-code blob-code-inner js-file-line">snmp-agent community write {{ simple['snmp']['write'] }}</td> </tr> <tr> <td id="L12" class="blob-num js-line-number" data-line-number="12"></td> <td id="LC12" class="blob-code blob-code-inner js-file-line">snmp-agent sys-info contact {{ simple['snmp']['syscontact'] }}</td> </tr> <tr> <td id="L13" class="blob-num js-line-number" data-line-number="13"></td> <td id="LC13" class="blob-code blob-code-inner js-file-line">snmp-agent sys-info location {{ simple['snmp']['syslocation'] }}</td> </tr> <tr> <td id="L14" class="blob-num js-line-number" data-line-number="14"></td> <td id="LC14" class="blob-code blob-code-inner js-file-line">snmp-agent sys-info version all</td> </tr> </table> </div> </div> <a href="#jump-to-line" rel="facebox[.linejump]" data-hotkey="l" style="display:none">Jump to Line</a> <div id="jump-to-line" style="display:none"> <!-- </textarea> --><!-- '"` --><form accept-charset="UTF-8" action="" class="js-jump-to-line-form" method="get"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /></div> <input class="linejump-input js-jump-to-line-field" type="text" placeholder="Jump to line…" aria-label="Jump to line" autofocus> <button type="submit" class="btn">Go</button> </form></div> </div> <div class="modal-backdrop"></div> </div> </div> </div> </div> <div class="container"> <div class="site-footer" role="contentinfo"> <ul class="site-footer-links right"> <li><a href="https://status.github.com/" data-ga-click="Footer, go to status, text:status">Status</a></li> <li><a href="https://developer.github.com" data-ga-click="Footer, go to api, text:api">API</a></li> <li><a href="https://training.github.com" data-ga-click="Footer, go to training, text:training">Training</a></li> <li><a href="https://shop.github.com" data-ga-click="Footer, go to shop, text:shop">Shop</a></li> <li><a href="https://github.com/blog" data-ga-click="Footer, go to blog, text:blog">Blog</a></li> <li><a href="https://github.com/about" data-ga-click="Footer, go to about, text:about">About</a></li> <li><a href="https://github.com/pricing" data-ga-click="Footer, go to pricing, text:pricing">Pricing</a></li> </ul> <a href="https://github.com" aria-label="Homepage"> <span aria-hidden="true" class="mega-octicon octicon-mark-github" title="GitHub "></span> </a> <ul class="site-footer-links"> <li>© 2016 <span title="0.04239s from github-fe141-cp1-prd.iad.github.net">GitHub</span>, Inc.</li> <li><a href="https://github.com/site/terms" data-ga-click="Footer, go to terms, text:terms">Terms</a></li> <li><a href="https://github.com/site/privacy" data-ga-click="Footer, go to privacy, text:privacy">Privacy</a></li> <li><a href="https://github.com/security" data-ga-click="Footer, go to security, text:security">Security</a></li> <li><a href="https://github.com/contact" data-ga-click="Footer, go to contact, text:contact">Contact</a></li> <li><a href="https://help.github.com" data-ga-click="Footer, go to help, text:help">Help</a></li> </ul> </div> </div> <div id="ajax-error-message" class="flash flash-error"> <span aria-hidden="true" class="octicon octicon-alert"></span> <button type="button" class="flash-close js-flash-close js-ajax-error-dismiss" aria-label="Dismiss error"> <span aria-hidden="true" class="octicon octicon-x"></span> </button> Something went wrong with that request. Please try again. </div> <script crossorigin="anonymous" src="https://assets-cdn.github.com/assets/compat-a0cee5d8d4fb535c0f41971d037b32e852a56ddca5bf67bb2124e426a2d813a5.js"></script> <script crossorigin="anonymous" src="https://assets-cdn.github.com/assets/frameworks-9ee55ceaf87fc34dc86334249fef6cbece88e815478e0fbe81642d57ed0fff89.js"></script> <script async="async" crossorigin="anonymous" src="https://assets-cdn.github.com/assets/github-1be19ad6629c8d2b52bb1b011c6b7ecf743db569054c1c0f36c8d9858ce3f640.js"></script> <div class="js-stale-session-flash stale-session-flash flash flash-warn flash-banner hidden"> <span aria-hidden="true" class="octicon octicon-alert"></span> <span class="signed-in-tab-flash">You signed in with another tab or window. <a href="">Reload</a> to refresh your session.</span> <span class="signed-out-tab-flash">You signed out in another tab or window. <a href="">Reload</a> to refresh your session.</span> </div> <div class="facebox" id="facebox" style="display:none;"> <div class="facebox-popup"> <div class="facebox-content" role="dialog" aria-labelledby="facebox-header" aria-describedby="facebox-description"> </div> <button type="button" class="facebox-close js-facebox-close" aria-label="Close modal"> <span aria-hidden="true" class="octicon octicon-x"></span> </button> </div> </div> </body> </html>
The requests library is reaching out and grabbing whatever we put into that first variable. If we look at the print contents, we can see the first line is <!DOCTYPE html> . So it looks like we're grabbing the rendered webpage, not just the contents of the file. Thankfully, looking at the GITHub website, there's an option to look at any of your files in raw mode. So let's grab that URL and try this again, ok?
comware_template = requests.get('https://raw.githubusercontent.com/netmanchris/Jinja2-Network-Configurations-Scripts/master/simple_comware.j2').text
print (comware_template)
#sysname config sysname {{ simple['hostname'] }} #vlan config {% for vlan in simple['vlans'] -%} vlan {{ vlan['id'] }} name {{ vlan['name'] }} description {{ vlan['description'] }} {% endfor %}#snmp_config snmp-agent snmp-agent community read {{ simple['snmp']['read'] }} snmp-agent community write {{ simple['snmp']['write'] }} snmp-agent sys-info contact {{ simple['snmp']['syscontact'] }} snmp-agent sys-info location {{ simple['snmp']['syslocation'] }} snmp-agent sys-info version all
Ahhhh... That's better.¶
Now we're going to load our network specific values which were stored in the YAML file in this post. But this time, we're going to load them directly from a private github repository.
The free GITHub accounts allow you to have public repositories, which means everyone can see what you're doing, but if you have a paid version, you can get private repositories for as little as five dollars a month.
The private repositories are secured and can only be accessed by someone with a GIThub username and password who has explicitly been given access to this repository.
I would say that it's probably a bad idea for us to keep any secure information like usernames, passwords, or SNMP strings in a online repository. But for my purposes, I don't have anythng of value in this lab environment so I'm not too worried about it.
First, I'm going to create an auth object, which is basically a single object that represents the username and password for my github account. In my case, I've got a file on my local hard drive that will automatically create the auth object for me.
In case you're interested, the file is called githubuser.py and contains the following code.
from requests.auth import HTTPBasicAuth
def gitcreds(): auth = HTTPBasicAuth('netmanchris', 'my_secret_password') return auth </code>
auth = githubuser.gitcreds() #you didn't think I was going to give you my password did you?
We'll now load the simple.yaml file like we did in this post but instead of opening it from a local file, we're going to load it directly from the raw version of the file on github. I'd give you the link but it's in a private repository, so you won't be able to access it anyways.
Thigs I want to point out
Make sense?
simple = yaml.load(requests.get('https://raw.githubusercontent.com/netmanchris/PrivateRepo/master/simple_config.yaml', auth=auth).text)
simple
{'hostname': 'testswitch', 'ip': '10.101.0.221', 'snmp': {'read': 'supersecret', 'syscontact': 'admin.lab.local', 'syslocation': 'lab', 'trap': [{'target': '10.101.0.200'}, {'target': '10.101.0.201'}, {'target': '10.101.0.202'}], 'write': 'macdonald'}, 'vlans': [{'description': 'management vlan', 'id': '10', 'name': 'management'}, {'description': 'users vlan', 'id': '15', 'name': 'users'}, {'description': 'phones vlan', 'id': '16', 'name': 'phones'}, {'description': 'servers vlan', 'id': '20', 'name': 'servers vlan'}]}
So looking at our list
So I guess we know what comes next, right?
We use the Template function to create a jinja2 template object and then we use the simple variable we created during the yaml section as input into the cw_template object.
cw_template = Template(comware_template)
type(cw_template)
jinja2.environment.Template
print (cw_template.render(simple=simple))
#sysname config sysname testswitch #vlan config vlan 10 name management description management vlan vlan 15 name users description users vlan vlan 16 name phones description phones vlan vlan 20 name servers vlan description servers vlan #snmp_config snmp-agent snmp-agent community read supersecret snmp-agent community write macdonald snmp-agent sys-info contact admin.lab.local snmp-agent sys-info location lab snmp-agent sys-info version all
So far we've only been rendering and printing configurations, but it would be kinda nice to be able to have these on disk so that we can open them in our favorite editor before we cut and paste them into a telnet session to our network device.
The next two commands simply write the rendered template to disk with the filename comware.cfg and then we open and print the file to screen just to make sure it worked.
with open('comware.cfg', "w") as file:
file.write(cw_template.render(simple=simple))
with open('comware.cfg') as file:
print (file.read())
#sysname config sysname testswitch #vlan config vlan 10 name management description management vlan vlan 15 name users description users vlan vlan 16 name phones description phones vlan vlan 20 name servers vlan description servers vlan #snmp_config snmp-agent snmp-agent community read supersecret snmp-agent community write macdonald snmp-agent sys-info contact admin.lab.local snmp-agent sys-info location lab snmp-agent sys-info version all
So far, we've come pretty far. We've written a couple of jinja templates, we've figure out how to store those files in a centralized control versioning system, but we're still cut'ing and past'ing those configurations ourselves which is not ideal.
In the next post, we'll look at using APIs to push the configuraiton directly to a configuraiton management tool.
Questions or comments? Feel free to post below!
@netmanchris