Snippets for the Season: Dynamic Applications Using Python

Tim May

EM7 G3 produced the ability to write snippet dynamic applications that use Python code to do collection against an almost endless supply of data. Anything that can be retrieved using Python can be dumped into the dynamic application engine and then alerted, evented, tracked, and ticketed against.

In this example, we will be using the paramiko Python module to log into a device using SSH, run a command, and get the output. The specific command  is the sar command to collect CPU information in Linux. EM7 helps the user manage credentials by storing them securely in the database until they are needed for collection.

Snippet Dynamic Applications have the credential assigned to the application passed in for use by the snippet. There are two things to know when editing Python in general.

  1. Whitespace is important
  2. Case is important

For all of you techie and code geeks out there, here is the quick version of writing snipped dynamic applications using Python. First we start with the imports and the command we wish to run on the target device.

<code> import re, time, socket, string import paramiko command = ‘/usr/bin/sar -u -P ALL 1’ </code>

Next, we add the credential handling which will decrypt the credential from EM7 and set it for use to individual variables inside the snippet.

<code> server = self.cred_details[‘cred_host’] user = self.cred_details[‘cred_user’] passwd = self.cred_details[‘cred_pwd’] port = self.cred_details[‘cred_port’] timeout = self.cred_details[‘cred_timeout’] </code>

We start a timer and set the standard output variable for use later. We use the timer to tell how long collection is taking in general.

<code> start_time = time.time() stdout = None </code>

Now we start by trying to make the SSH connection, run the command, and set the output variable. We check to see if there are any errors through the exception handling in Python. If an exception is encountered, we spawn an internal event to alert the user to the problem.

<code> try: ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(server, username=user, password=passwd, port=int(port), timeout=float(timeout)) stdin, stdout, stderr = ssh.exec_command(command) except paramiko.BadHostKeyException, e: self.internal_alerts.append((SNIPPET_MSG, “App:%s, Could not connect to remote device, bad host key detected: %s” % (self.app_id, str(e)))) except paramiko.AuthenticationException, e: self.internal_alerts.append((SNIPPET_MSG, “App:%s, Authentication failed, check credential id: %s, error: %s” % (self.app_id, self.cred_details[‘cred_id’], str(e)))) except paramiko.SSHException, e: self.internal_alerts.append((SNIPPET_MSG, “App:%s, SSH failure: %s” % (self.app_id, str(e)))) except socket.error, e: self.internal_alerts.append((SNIPPET_MSG, “App:%s, Socket failure: %s” % (self.app_id, str(e)))) except Exception, e: self.internal_alerts.append((SNIPPET_MSG, “App:%s, General failure: %s” % (self.app_id, str(e)))) </code>

We setup the Python list variables that will be used to store the information for retrieval later in the snippet. EM7 expects a list of tuples to be returned.

<code> cpu = [] user = [] nice = [] system = [] iowait = [] steal = [] idle = [] </code>

We need to regex the output to make sure it is the output we want. SAR will output the current values as well as system averages. We are only interested in the current value so we look for a timestamp at the start of a line. If it is there, we separate the data by whitespace and then look for the given columns in the order they come back. When we get valid data, we append a Python tuple consisting of the current index and value. This list of tuples is the format the EM7 dynamic application engine expects to be returned at the end of the snippet.

<code> if stdout is not None: for line in stdout.readlines(): match_object = re.search(r”””dd:dd:ddsDDs+(.*)”””, line) if match_object is not None: all_groups = match_object.groups() current_line = string.split(all_groups[0]) if len(current_line) == 7 and current_line[0] != “CPU”: index = current_line[0] cpu.append((index, current_line[0])) user.append((index, current_line[1])) nice.append((index, current_line[2])) system.append((index, current_line[3])) iowait.append((index, current_line[4])) steal.append((index, current_line[5])) idle.append((index, current_line[6])) </code>

We now do some cleanup and close the SSH connection and stop the timer that was started earlier.

<code> ssh.close() elapsed_time = time.time() – start_time </code>

Lastly, we add the code to handle splitting the lists by collection object so the dynamic application engine will align the data with the correct object id. The format EM7 expects is a Python dictionary with a key of result/list of values and the time it took to collect. The value pair for the oid_detail[“result”] key is the lists we setup earlier.

<code> for group, oid_group in self.oids.iteritems(): for obj_id, oid_detail in oid_group.iteritems(): if oid_detail[‘oid_type’] != snippet_id: # This collection object is obtained from a different Snippet continue oid = oid_detail[“oid”] if oid == ‘CPU’ and len(cpu) > 0: oid_detail[“result”] = cpu oid_detail[“oid_time”] = elapsed_time elif oid == ‘User’ and len(user) > 0: oid_detail[“result”] = user oid_detail[“oid_time”] = elapsed_time elif oid == ‘Nice’ and len(nice) > 0: oid_detail[“result”] = nice oid_detail[“oid_time”] = elapsed_time elif oid == ‘System’ and len(system) > 0: oid_detail[“result”] = system oid_detail[“oid_time”] = elapsed_time elif oid == ‘IOWait’ and len(iowait) > 0: oid_detail[“result”] = iowait oid_detail[“oid_time”] = elapsed_time elif oid == ‘Steal’ and len(steal) > 0: oid_detail[“result”] = steal oid_detail[“oid_time”] = elapsed_time elif oid == ‘Idle’ and len(idle) > 0: oid_detail[“result”] = idle oid_detail[“oid_time”] = elapsed_time </code>

The entire snippet code can be downloaded here. When the dynamic application is assembled including collection objects, presentation objects, and the linkage to the Python code snippet, the following is what EM7 will show in the graphing engine. blog-201012-cpu-grap-from-sar The value in this snippet is we can separate each processor out into its values. Net-SNMP will roll all of the values up into a single value which spans CPUs. This gets difficult to see when there are two 4 core processors which would show up as 1 averaged processor to Net-SNMP and will show up as 8 total processors to SAR. You can download the Python report here. This is the sixth in a series of posts about EM7. For more, click here.

Share This Post

Most Popular

Archive

Comments

  • Brad Wigginton

    I’ve got an issue with EM7 reporting on Cisco c-Series endpoints where I get a minor severity post stating “App: 703, Snippet: 748 reported a collection problem…” what would cause this error?