The IT industry is at a crossroads. While the demand for IT professionals, including network engineers, is skyrocketing, the number of candidates suitable for these positions is low.
The limited candidate pool makes it more crucial than ever for organizations to provide early-career professionals with opportunities to develop their skills and grow their knowledge of the network automation industry.
Recognizing the need to find and keep the right talent, Network to Code launched its own talent development program, NTC University, designed to propel the network engineers of today into the network automation engineers of the future.
So, what makes NTC University the go-to development program for aspiring network engineers and Network to Code the employer of choice?
Let’s find out!
Growing Demand for Network Engineers
The job market for network engineers is growing rapidly, with a projected 6% increase in employment from 2016 to 2026. With the increasing reliance on technology, the need for companies to maintain and secure their networks is more important than ever.
Network engineers are one of the most wanted professionals in the US. Despite the growing demand for network engineers, the industry is experiencing a need for more qualified professionals in the field. This shortage is due to the rapidly changing nature of technology, which requires constant learning and adaptation. Network engineers have not been offered career growth opportunities in the industry.
What Is NTC University?
NTC University is a trailblazing new corporate development program from Network to Code for early-career network engineers. The ten-week immersive program will provide the necessary technical education and consulting skill set for a select group of network engineering professionals. With acceptance into this program, individuals will join Network to Code as full-time Associate Engineers before the start of the program in the fall of 2023.
Participating in this talent development program means you will join our team as a full-time employee from day one and represent our core values in all you do. We are looking for results-driven individuals and creative problem solvers who love to do it differently and want to make an impact on the future of Network Automation in real time.
After completing the ten-week program, participants will join a Network Automation team at Network to Code, starting to work on customer projects delivering solutions for clients, with job shadow and mentorship support for an entire year.
And the benefits are invaluable.
Technical Education Provided
NTC University offers a comprehensive technical education that covers a wide range of topics. From the fundamentals of networking to advanced automation techniques, network engineers have access to a wealth of knowledge that can help them excel in their careers at Network to Code and beyond. The curriculum is designed to be hands-on, allowing participants to gain practical experience to apply in real-world scenarios at Network to Code after completing the program.
Consulting Skill Set Development
In addition to technical education, NTC University also offers training in consulting skills, including communication, project management, and problem-solving skills. With NTC University, network engineers can develop a well-rounded skill set to help them succeed in their new role at Network to Code.
Real-World Experience from Network Automation Leader
NTC University uniquely provides network engineers with real-world experience from a network automation leader named to the Inc. Best Workplaces list along with special recognition in the Prosperous and Thriving category. Participants will have access to dedicated instructors, shadow engineers, and mentors to set them up for success in their new position at Network to Code. The instructors are experts in network automation and have years of experience working with some of the world’s largest and most complex networks.
Propelling Engineers into the Future with NTC University
Through NTCU, Network to Code aims to create a clear career path to propel today’s network engineers into the future as network automation engineers.
In the ten-week program, eligible candidates who are located in the United States and have at least two years of network engineering experience, a basic understanding of Python and data structures, and a passion for network automation will learn everything from Python & Django Fundamentals and Network Automation with Python & Ansible to Network Source of Truth with Nautobot and Nautobot App Development.
Network to Code will host an informational session on NTC University for interested network engineers to learn more about the program. The next session will be on May 16th at 1 p.m. ET. So save your seat and learn more about this trailblazing new corporate development program from Network to Code.
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.
On the surface, all network engineers have a good understanding about what configuration compliance, or golden config, is. However, I’ve found the devil is in the details, and there are many different ideas as to what it should be. In this article, we will explore what some of those views are and some of the pros/cons for them.
Bulk Matching
This works best for “global configurations” such as ntp, dns, snmp, etc. The idea is that you have a standard of what the configurations should be, and you should ensure the actual configurations are the same.
This works well if the configurations are truly the same with a pattern, as described in this pseudo code:
expected_config ="ntp server 10.1.1.1\nntp server 10.1.1.2\nntp server 10.1.1.3 prefer"actual_config =run_ios_command("show run | in ^ntp server")if expected_config == actual_config:returnTrueelse:returnFalse
This tends to not scale well when you have exceptions, a lot of regionality (e.g., differences for region-based standards such as eu, am, ep, etc.), exceptions to the rule (e.g., if a site has a local ntp server, use it), and does not really consider the configurations that will always be different like IPs on interfaces, BGP ASNs, VLANs, etc.
Regex Pattern Matching
Sometimes, you are not as concerned about the actual data, such as whether or not the NTP servers are specific IPs, but instead are concerned that there are NTP servers configured. In such situations you can set up regex to match against your configurations.
Block Start:interface(.*)Block End:!Condition A: Config Blockmust not containip address(10\..*)\s(.*)Condition B: Config Textmust contain only:Must contain these lines:ntp server 169\.243\.103\.34ntp server 170\.242\.62\.16ntp server 170\.242\.62\.17ntp server 169\.243\.226\.94But must not have any additional lines containing:ntp server(.*)Logic: A AND B
As you can see, you can use regex to perform “greedy” matches, such as ip address (10\..*)\s(.*), as well as specific matches, such as ntp server 169\.243\.103\.34.
There are also some scaling concerns with this approach, such as which devices does this template apply to, which templates are applied to a device, complex regex matching that quickly gets out of control, and not providing a path to “fix” the configurations.
Profiling Configurations
As you will note, the previous options made it difficult to scale beyond the global configurations. Developing compliance on configurations like interface can be rather difficult, if not impossible, in them.
With profiling the configurations, we can build strategies to pull out the relevant data and ensure a configuration can be rebuilt to the actual configurations. Well, that was a confusing mouthful, so let’s break this down a bit.
Grab a piece of configuration, such as all configuration under “interface GigabitEthernet0/1”.
We will call this actual_configuration.
Grab the detail from that configuration that you would use to profile it, such as the description and VLAN.
Use that data with predefined templates and process through a templating engine.
We call this expected_configuration.
Compare actual_configuration and expected_configuration and see whether they are the same.
If there are configs in actual_configuration and not in expected_configuration, there are unexpected configurations.
If there are configs in expected_configuration and not in actual_configuration, there are missing configurations.
Well, this is still a bit much, how about a diagram?
All make sense? If not, one more effort with actual code:
With this approach you solve many of the challenges of comparing different types of configurations. That being said, numerous challenges remain.
Each configuration stanza requires some custom code
Exception management is difficult
For example, you want to add broadcast suppression on twenty interfaces within your entire org, how do you handle that?
In some cases you do not care about the current configuration, you simply want the configuration to match the expected; so you must support this solution and another solution as well.
Intended State vs Actual State
Having built many such solutions, the idea of building a comparison of the actual state vs intended seemed the most logical. In such a design, the lion’s share of the work is how to generate configurations, in a “traditional” Infrastructure as Code (IaC) approach. With IaC, you generate your configurations (within networking) generally by combining the data with Jinja templates.
Let’s break down this process a bit.
Obtain the actual configuration from the backup
Parse out the relevant configuration, often by breaking up into features (think stanza levels of configurations)
We will call this actual_configuration.
Generate the intended configuration
We will call this intended_configuration.
Compare the two configuration parts
To help bring this to life, here is a diagram of how this works:
In pursuing this approach, you get the direct benefits for configuration compliance of:
Having a single solution for any CLI-based configurations, regardless of vendor
Limiting the amount of code for any given configuration (to nearly zero)
Providing a platform for exception management
Providing a path to fix the configurations
Note: Though outside the scope of this blog, the ability to remedy configurations is generally predicated on having both an actual and an intended state.
Additionally, there are the collateral benefits of:
Providing a reason to develop an IaC solution
Providing a reason to build out configurations
Providing a reason to populate a Source of Truth
To finally drive home how this works, let’s review some code.
Basic Setup
>>> import jinja2>>> from netutils.config import compliance>>>>>> def regen_cfg(vars):... template_str =""""""... environment = jinja2.Environment()... template = environment.from_string(template_str)...return template.render(**vars)...>>># This is our pseudo SoT>>> vars ={}>>> vars['interface_vars']=[{'interface':'GigabitEthernet0/1','description':'USER PORT','vlan':'205'}]>>>>>> network_os ="cisco_ios">>> features =[...{"name":"interface","ordered":True,"section":["interface "]},...]>>>
It may not be immediately obvious, but the key is in the feature definition features = [{"name": "interface", "ordered": True, "section": ["interface "]}]. This is the only thing that needs to change when adding additional features. This truly becomes powerful once you have an SoT and have built out your IaC processes.
The app provides tooling and ease of use around the processes, which makes it more consumable, but the crux of what is happening is described in these last few paragraphs and code snippets.
Custom Business Logic
While not more strictly defined, it is important to cover custom business logic. There are times when you may only care about the application of certain features but not check beyond that. Let’s take an example used in Nautobot Golden Config custom compliance engine.
In the above case you are simply enforcing that if neighbor 70.70.70.70 is found, there is a configured password on it. The obvious downside to this is every situation must be handled with custom code, and you are not reviewing all of the configuration or even a majority of the configuration.
Linting
In some cases you are truly only looking for certain conditions. This can be nice, since it applies more generically and has good utility around ensuring security configurations are applied correctly. Services such as STIG or Cisco Config Analysis Tool are largely based on the same concept, which is to confirm that a piece of configuration is on or specifically not on.
We can take a look at a netlint that was built by fellow Network to Coder Leo Kirchner.
>>> from netlint.checks.checker import Checker>>> from netlint.checks.utils import NOS>>>>>> configuration =[..."feature ssh",..."feature bgp",..."hostname test.local"...]>>>>>> checker =Checker()>>>>>> checker.run_checks(configuration, NOS.CISCO_NXOS)False>>> checker.check_results{'NXOS101': None,'NXOS102':CheckResult(text='BGP enabled but never used.', lines=['feature bgp']),'NXOS103': None,'NXOS104': None,'VAR101': None,'VAR102': None,'VAR103': None}>>>
Conclusion
Throughout my career, I have personally deployed and built each of these types of systems. However, I truly believe that the only long-term method to scale is provided in the “Intended State vs Actual State” section and used within Nautobot Golden Config. Any other method is likely good to get quick results, but tends to not work in situations more complicated than the initial POC. The collateral benefits are also equally compelling in themselves.
That being said, would love to hear your feedback. Are there any other types of golden config that I have missed? If so, look forward to seeing you in the comments.
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.
This is part of a series of posts intended to provide an understanding of Network Automation Principles.
The term inheritance has its origin rooted in object-oriented programming, dating back to the ’60s. As the name suggests, it describes the relationship between objects and how their attributes are handed down, using similar hierarchical relationship naming as used in a family tree (parent, child, grandparent, etc.).
Inheritance is one of the tools in the arsenal that allow programmers to simplify their code and generally keep it more DRY.
Inheritance in Computer Science
A common example used to portray this would be classifying a vehicle, specifically with vehicle being the parent object and vehicle types such as cars, vans, motorcycles being the child object.
One thing you may notice here is that while Router has the property of tunneling_protocols, the Switch does not. The same is true in reverse for rmon support. So with the use of inheritance, you can use the same interface as the Router for the properties that are on both or inherited from the parent, which supports the ability to be DRY.
You can add multiple levels of inheritance in Python. Oftentimes a strategy would be to use a Mixin, which is a conceptual idea of a class that has the sole use of being mixed in with other classes. Take the following example.
You can see that SuperNetworkDeviceMixin can be used to add the properties cpu and routing_protocols to the Router class.
This ability to have multiple levels of inheritance is based on the Method Resolution Order (MRO), if you are interested in learning more.
Inheritance in Ansible
Ansible provides the ability to have set the hash_behaviour, however the default is replace. With this, it works the same way as inheritance, in that the more specific attribute overrides the parent.
As the ntp would be inherited from the eu.yml file and dns inherited from the all.yml file. The layout of the inheritance structure is found in Ansible Variable Precedence documentation.
Real-Life Use Case with NAPALM
NAPALM heavily relies on inheritance to provide a consistent interface to many vendors, while still having drastically different code for each vendor. In this seriously truncated code taken directly from NAPALM’s source code, you can see how the base class (NetworkDriver) works and how a child class (IOSDriver) is implemented.
classNetworkDriver(object):defget_ntp_peers(self) -> Dict[str, models.NTPPeerDict]: """ReturnstheNTPpeersconfigurationasdictionary.ThekeysofthedictionaryrepresenttheIPAddressesofthepeers.Innerdictionariesdonothaveyetanyavailablekeys.Example::{'192.168.0.1':{},'17.72.148.53':{},'37.187.56.220':{},'162.158.20.18':{}}""" raise NotImplementedErrorclassIOSDriver(NetworkDriver):defget_ntp_peers(self): """Implementationofget_ntp_peersforIOS."""ntp_stats = self.get_ntp_stats()return{ napalm.base.helpers.ip(ntp_peer.get("remote")):{} for ntp_peer inntp_stats if ntp_peer.get("remote")}
This way, each class that inherits from the base class clearly indicates which methods it implements (by explicitly overwriting those methods) and which ones it doesn’t (and thus will raise a NotImplementedError if called).
Inheritance in Django
One great example of Inheritance is Django. Its usage of object-oriented programming can be amazing when you understand it and frustrating when you don’t. Knowing how the MRO works and is implemented in Django is a must to start to understand how Django works. In that pursuit, I have found the “classy” pages for Django and DRF to be helpful.
Conclusion
Inheritance is used extensively throughout object oriented-programming languages such as Python. Additionally, there are concepts are used elsewhere, such as in Ansible’s variable structure.
Understanding the concept can help you in your day-to-day automation as well as provide the ability to build more scalable solutions.
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.