Creating Python Packages

For a project involving Zenoss Core 4 and a HaaS solution maintained by another team, we needed a module to interact with the Zenoss JSON API to get the list of events for specific devices. Browsing around I found this python-zenoss module to work with the Zenoss JSON API. However I was experiencing some issues when installing it, so I decided to create my own Python package to provide a different way to interact with the Zenoss JSON API according to our specific needs.

The package would be installed locally using pip, and all its functionality should be easily accessible using from and import commands in Python.

To start working in our package we will create a base directory. The directory's name will resemble our package's name. For naming, we should following these guidelines:

The package contents are the following:

my_api/
├── __init__.py
├── api.py
└── setup.py

The __init__.py file tells Python that this directory should be treated as a Python package. Inside we can include some import statements to import the modules we need:

from api import Api

In the above code from api refers to api.py inside our package, and import Api refers to the Api class defined in that same file. That is the class that represents the API access to the Zenoss JSON API.

Let's take a look at that class:

api.py
class Api(object):
  def __init__(self, host=None, username='admin', password='zenoss', debug=False):
    """
    Initialize the API connection, log in, and store authentication cookie
    """
    self.__host = host

    # Use the HTTPCookieProcessor as urllib2 does not save cookies by default
    self.urlOpener = urllib2.build_opener(urllib2.HTTPCookieProcessor())
    if debug: self.urlOpener.add_handler(urllib2.HTTPHandler(debuglevel=1))
    self.reqCount = 1

    # Contruct POST params and submit login.
    loginParams = urllib.urlencode(dict(
                    __ac_name = username,
                    __ac_password = password,
                    submitted = 'true',
                    came_from = host + '/zport/dmd'))
    self.urlOpener.open(host + '/zport/acl_users/cookieAuthHelper/login',
                        loginParams)

Basically we are initializing an instance of Api by passing a hostname (which should be the IP_ADDRESS:PORT of your Zenoss instance), along with the Zenoss username and password. When the instance is created, it will try to authenticate with Zenoss.

If our Api instance authenticated successfully, we can begin calling our Python methods to query the Zenoss JSON API. As I mentioned in the beginning of this post, we wanted to get the events for specific devices, so we can add a method for that:

def get_events(self, device=None, component=None, eventClass=None):
    data = dict(start=0, limit=100, dir='DESC', sort='severity')
    data['params'] = dict(severity=[5,4,3,2], eventState=[0])

    if device: data['params']['device'] = device
    if component: data['params']['component'] = component
    if eventClass: data['params']['eventClass'] = eventClass

    return self._router_request('EventsRouter', 'query', [data])['result']

Now the last piece of our Python package is the setup.py file. This file will contain the meta-data of our package, and is used by pip when installing the package in our system:

setup.py
from setuptools import setup

setup(name='my_api',
    version='1.0.0',
    description='Zenoss API module',
    author='Andres Alvarez',
    author_email='myemail@email.com',
    license='MIT',
    py_modules=['pdcm',],
    zip_safe=False)

Once everything is ready we can proceed to install our package using pip:

pip install my_api

And once it is successfully installed, we can test that our package can be used by opening the Python interactive console (type python in your terminal)

from my_api import Api
from pprint import pprint

api = Api(host='http://my-ip:8080', username='admin', password='zenoss')

events = api.get_events(device='HSL19023')['events']

pprint(events)
packaging python zenoss

Comments

comments powered by Disqus