While getting ready for Cisco Live, amwhaley and I were discussing DevOps and continuous integration.  We were already planning to upgrade the Coding 100 series labs, and thought that we should update the code to be more in line with a continuous integration model.  While we're not done, we wanted to give you an early look into what we're up to.


What is Continuous Integration?

Continuous Integration or just "CI" is both a methodology that comes down to having automated testing as part of your development process.  Usually, you run a build server, and there are many to choose from out there.  Some of the well known ones are Jenkins, Travis,, Shippable.  Whichever one you pick, you typically have to set it up so that the build server is integrated with your source control system.  The build server communicates with the source control system either through polling or via webhooks to know when you check in code.  Because the build server is configured to run your code tests after it builds your project, it can act as an impartial middleman in your development process.  If your build and tests succeed, then you can configure the build server to perform additional steps.  For example, for a web app, you might want to take the built code, and just go ahead and deploy it on your staging server.  Tada!  Now you're in the realm of Continuous Deployment, which is one of the lynchpins of the DevOps model. We can save that for a later blog post.


Getting down to business


Here's an example of continuous integration using some of our Learning Labs sample code.  This example throws in the bonus of testing against the always-on APIC-EM server in the DevNet Sandbox.  In this example, we created a new branch (clus-updates) in our Coding 102 coding skills Learning Lab to test this out.


Let's create a test case for what we want to do.  The setup(self) and tearDown(self) methods are part of the unittest library.  These let you set up and clean up the test environment before you execute your actual test.


import os
import unittest
import json
import apicEm1

class Coding102TestCase(unittest.TestCase):

     def setUp(self):

 = apicEm1

     def tearDown(self):

          print("tear down")

     def test_hello(self):

          result =
          self.assertTrue(result is not None)
          self.assertEquals(200, result.status_code) 

if __name__ == '__main__':


Let's break this down a bit:


result =


This executes the hello() method from the module that you're going to write (or in our case refactor) and stores it in result.


self.assertTrue(result is not None)


This uses the unittest's built in method to test whether the result is not empty.


self.assertEquals(200, result.status_code)


Finally, we test whether the result came back with an HTTP status code of 200, meaning the server reports the call succeeded successfully.


Now, let's refactor our code!  Here's the result.


import requests

def hello():
  # put the ip address or dns of your apic-em controller in this url
  url = ''

  # this statement performs a GET on the specified url
  response = requests.get(url, verify=False)

  return response

# This is special python syntax that enables you to run this script
# directly or use it as a module and test your code!
# Read more about it here:
if __name__ == '__main__':

  # this statement calls the method hello() and
  # stores it into result
  result = hello()

  # print the result as text.
  # The responses library provides the .text convenience method to access
  # the result body or text


This code creates a method hello(), which uses the python requests library to fetch the result from the DevNet Sandbox APIC-EM server.  The Python __main__ method executes the hello() method, and then prints the result.  This code has been refactored from the original code example to be testable, which is very important for using CI.


In Part 2, we'll show you how we integrated with to get automated builds and tests executed.