From 10d1b6aa58f08584fe76744e71a290aedeec917e Mon Sep 17 00:00:00 2001 From: "joncutrer@gmail.com" Date: Wed, 4 Jan 2017 21:43:17 -0600 Subject: [PATCH 1/2] Siteleaf Setup --- .gitignore | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 From 0fd921ad936acf8b437475d79a6177ce398c18f0 Mon Sep 17 00:00:00 2001 From: "joncutrer@gmail.com" Date: Wed, 4 Jan 2017 21:43:23 -0600 Subject: [PATCH 2/2] Updated Config and 7 other files --- .gitattributes | 22 + .gitignore | 215 ++++++ CNAME | 1 + README.md | 3 + _config.yml | 11 + home.markdown | 8 + ...a Dell PowerEdge Server using pysnmp.ipynb | 714 ++++++++++++++++++ ... RSS News headlines using feedparser.ipynb | 139 ++++ 8 files changed, 1113 insertions(+) create mode 100644 .gitattributes create mode 100644 CNAME create mode 100644 README.md create mode 100644 _config.yml create mode 100644 home.markdown create mode 100644 net/snmp/Get Temperature and other environmental data from a Dell PowerEdge Server using pysnmp.ipynb create mode 100644 web/rss/How to Parse and Combine RSS News headlines using feedparser.ipynb diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..412eeda --- /dev/null +++ b/.gitattributes @@ -0,0 +1,22 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp +*.sln merge=union +*.csproj merge=union +*.vbproj merge=union +*.fsproj merge=union +*.dbproj merge=union + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore index e69de29..b9d6bd9 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,215 @@ +################# +## Eclipse +################# + +*.pydevproject +.project +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + + +################# +## Visual Studio +################# + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +build/ +[Bb]in/ +[Oo]bj/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml +*.pubxml + +# NuGet Packages Directory +## TODO: If you have NuGet Package Restore enabled, uncomment the next line +#packages/ + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml +*.pfx +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +############# +## Windows detritus +############# + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + + +############# +## Python +############# + +*.py[co] + +# Packages +*.egg +*.egg-info +dist/ +build/ +eggs/ +parts/ +var/ +sdist/ +develop-eggs/ +.installed.cfg + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.tox + +#Translations +*.mo + +#Mr Developer +.mr.developer.cfg diff --git a/CNAME b/CNAME new file mode 100644 index 0000000..7abda01 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +python-tutorials.siteleaf.net \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..4ac9857 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +My collection of python tutorials and sample code in the form of IPython Notebook files. + +Python Tutorials http://jcutrer.com/howto/dev/python/ \ No newline at end of file diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..18c351c --- /dev/null +++ b/_config.yml @@ -0,0 +1,11 @@ +--- +title: Python Tutorials +timezone: UTC +collections: + posts: + title: Posts + output: true + uploads: + title: Uploads + output: true +Foo: Bar diff --git a/home.markdown b/home.markdown new file mode 100644 index 0000000..1239f0b --- /dev/null +++ b/home.markdown @@ -0,0 +1,8 @@ +--- +title: Home +date: 2017-01-05 03:38:00 Z +--- + +My collection of python tutorials and sample code in the form of IPython Notebook files. + +Python Tutorials http://jcutrer.com/howto/dev/python/ \ No newline at end of file diff --git a/net/snmp/Get Temperature and other environmental data from a Dell PowerEdge Server using pysnmp.ipynb b/net/snmp/Get Temperature and other environmental data from a Dell PowerEdge Server using pysnmp.ipynb new file mode 100644 index 0000000..569ad68 --- /dev/null +++ b/net/snmp/Get Temperature and other environmental data from a Dell PowerEdge Server using pysnmp.ipynb @@ -0,0 +1,714 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This notebook will teach you how to query snmp data from a Dell PowerEdge server. Once OpenManage software is installed on a Dell server, a ton of information is made available via SNMP including...\n", + "\n", + "* Chassis Temperature\n", + "* Fan(s) Speed\n", + "* Chassis Intrusion Switch\n", + "* Hard Drive Health\n", + "* Power Supply Status, Voltages, and Consumption\n", + "\n", + "\n", + "### Prerequisites\n", + "\n", + "1.) Install the pysnmp package\n", + "\n", + "```\n", + "C:\\> pip install --upgrade pysnmp\n", + "Collecting pysnmp\n", + "...\n", + "Installing collected packages: pysmi, pysnmp\n", + "Successfully installed pysmi-0.0.6 pysnmp-4.3.1\n", + "```\n", + "\n", + "2.) A Dell PowerEdge Server running Windows Server 2008 or newer with Dell Open Manage Installed.\n", + "\n", + "3.) You will also need to install and configure SNMP support on the target Windows Server machine.\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you search for pysnmp example code you will find two type, Synchronous and Asynchronous. The following code is an example of a synchronous SNMP Get found in the old pysnmp manual\n", + "\n", + "http://pysnmp.sourceforge.net/examples/current/v3arch/oneliner/manager/cmdgen/get-v2c.html" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false, + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "SNMPv2-SMI::enterprises.674.10892.1.300.10.1.8.1 = b'Dell Inc.'\n", + "SNMPv2-SMI::enterprises.674.10892.1.300.10.1.9.1 = b'PowerEdge R720'\n" + ] + } + ], + "source": [ + "from pysnmp.entity.rfc3413.oneliner import cmdgen\n", + "import time\n", + "\n", + "SNMP_HOST = '192.168.1.60'\n", + "SNMP_PORT = 161\n", + "SNMP_COMMUNITY = 'public'\n", + "\n", + "\n", + "cmdGen = cmdgen.CommandGenerator()\n", + "\n", + "errorIndication, errorStatus, errorIndex, varBinds = cmdGen.getCmd(\n", + " cmdgen.CommunityData(SNMP_COMMUNITY),\n", + " cmdgen.UdpTransportTarget((SNMP_HOST, SNMP_PORT)),\n", + " '1.3.6.1.4.1.674.10892.1.300.10.1.8.1',\n", + " '1.3.6.1.4.1.674.10892.1.300.10.1.9.1'\n", + ")\n", + "\n", + "# Check for errors and print out results\n", + "if errorIndication:\n", + " print(errorIndication)\n", + "else:\n", + " if errorStatus:\n", + " print('%s at %s' % (\n", + " errorStatus.prettyPrint(),\n", + " errorIndex and varBinds[int(errorIndex)-1] or '?'\n", + " )\n", + " )\n", + " else:\n", + " for name, val in varBinds:\n", + " print('%s = %s' % (name.prettyPrint(), val.prettyPrint()))\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Throughout the rest of this notebook we will stick with the Synchronous type code. We are only fetching a few data points and there is no need to add complexity of performing Asynchronous operations.\n", + "\n", + "Next, we will create a snmpget() function that will encapsulate the above code and make it reusable.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def snmpget(oid):\n", + " \n", + " from pysnmp.entity.rfc3413.oneliner import cmdgen\n", + " \n", + " global SNMP_HOST\n", + " global SNMP_PORT\n", + " global SNMP_COMMUNITY\n", + " \n", + " cmdGen = cmdgen.CommandGenerator()\n", + "\n", + " errorIndication, errorStatus, errorIndex, varBinds = cmdGen.getCmd(\n", + " cmdgen.CommunityData(SNMP_COMMUNITY),\n", + " cmdgen.UdpTransportTarget((SNMP_HOST, SNMP_PORT)),\n", + " oid\n", + " )\n", + " \n", + " # Check for errors and print out results\n", + " if errorIndication:\n", + " print(errorIndication)\n", + " else:\n", + " if errorStatus:\n", + " print('%s at %s' % (\n", + " errorStatus.prettyPrint(),\n", + " errorIndex and varBinds[int(errorIndex)-1] or '?'\n", + " )\n", + " )\n", + " else:\n", + " for name, val in varBinds:\n", + " #print('%s = %s' % (name.prettyPrint(), val.prettyPrint()))\n", + " return val\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With everything now contained inside the snmpget() function we can call the function for each OID we want to query." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false, + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dell Inc.\n" + ] + } + ], + "source": [ + "answer = snmpget('1.3.6.1.4.1.674.10892.1.300.10.1.8.1')\n", + "print(answer)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that we are getting the data, lets apply some formatting." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Make: Dell Inc.\n", + "Model: PowerEdge R720\n" + ] + } + ], + "source": [ + "print( 'Make: ' + snmpget('1.3.6.1.4.1.674.10892.1.300.10.1.8.1') )\n", + "print( 'Model: ' + snmpget('1.3.6.1.4.1.674.10892.1.300.10.1.9.1') )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, lets fetch some data about the power supply amperage and total watts consumed. You may get different results if your server does not have redundant(2) power supplies." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PS1 Current 1: 16 AMPS\n", + "PS2 Current 2: 0 AMPS\n", + "System Board Pwr Consumption: 196 Watts\n" + ] + } + ], + "source": [ + "print( snmpget('1.3.6.1.4.1.674.10892.1.600.30.1.8.1.1') + ': ' +\n", + " str(snmpget('1.3.6.1.4.1.674.10892.1.600.30.1.6.1.1')) + ' AMPS')\n", + "print( snmpget('1.3.6.1.4.1.674.10892.1.600.30.1.8.1.2') + ': ' +\n", + " str(snmpget('1.3.6.1.4.1.674.10892.1.600.30.1.6.1.2')) + ' AMPS')\n", + "print( snmpget('1.3.6.1.4.1.674.10892.1.600.30.1.8.1.3') + ': ' +\n", + " str(snmpget('1.3.6.1.4.1.674.10892.1.600.30.1.6.1.3')) + ' Watts')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So far, we have called snmpget() individually to get data. Lets modify snmpget to accept a list of OIDs and return a list of return values.\n", + "\n", + "We will progressivly modify our snmpget() function to accomplish this. We add two additional arguments to the function oid2, oid3. While this is not ideal the getCmd() wants each addition oid as an additional command line argument.\n", + "\n", + "Lets focus on the return values. Instead of iterating over varBinds we will extract the values and return a simple list or singular value if the list's length is 1." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def snmpget(oid, oid2='', oid3=''):\n", + " \n", + " from pysnmp.entity.rfc3413.oneliner import cmdgen\n", + " \n", + " global SNMP_HOST\n", + " global SNMP_PORT\n", + " global SNMP_COMMUNITY\n", + " \n", + " cmdGen = cmdgen.CommandGenerator()\n", + "\n", + " errorIndication, errorStatus, errorIndex, varBinds = cmdGen.getCmd(\n", + " cmdgen.CommunityData(SNMP_COMMUNITY),\n", + " cmdgen.UdpTransportTarget((SNMP_HOST, SNMP_PORT)),\n", + " oid,\n", + " oid2,\n", + " oid3\n", + " )\n", + " \n", + " # Predefine our results list \n", + " results = []\n", + " \n", + " # Check for errors and print out results\n", + " if errorIndication:\n", + " print(errorIndication)\n", + " else:\n", + " if errorStatus:\n", + " print('%s at %s' % (\n", + " errorStatus.prettyPrint(),\n", + " errorIndex and varBinds[int(errorIndex)-1] or '?'\n", + " )\n", + " )\n", + " else:\n", + " for name, val in varBinds:\n", + " results.append( val )\n", + " \n", + " if len(results) == 1:\n", + " return results[0]\n", + " else:\n", + " return results\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false, + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PS1 Current 1\n", + "PS2 Current 2\n", + "System Board Pwr Consumption\n" + ] + } + ], + "source": [ + "results = snmpget( '1.3.6.1.4.1.674.10892.1.600.30.1.8.1.1', \\\n", + " '1.3.6.1.4.1.674.10892.1.600.30.1.8.1.2', \\\n", + " '1.3.6.1.4.1.674.10892.1.600.30.1.8.1.3' )\n", + "\n", + "for ans in results:\n", + " print(ans)\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The function now returns a list of values but our approach to accepting additional arguments is not very flexible. As you can see we get an error when we try to request anything other than 3 oids." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "ename": "IndexError", + "evalue": "string index out of range", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mIndexError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mresults\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0msnmpget\u001b[0m\u001b[1;33m(\u001b[0m \u001b[1;34m'1.3.6.1.4.1.674.10892.1.600.30.1.8.1.1'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'1.3.6.1.4.1.674.10892.1.600.30.1.8.1.3'\u001b[0m \u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[1;32m\u001b[0m in \u001b[0;36msnmpget\u001b[1;34m(oid, oid2, oid3)\u001b[0m\n\u001b[0;32m 14\u001b[0m \u001b[0moid\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 15\u001b[0m \u001b[0moid2\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 16\u001b[1;33m \u001b[0moid3\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 17\u001b[0m )\n\u001b[0;32m 18\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mC:\\Anaconda3\\lib\\site-packages\\pysnmp\\entity\\rfc3413\\oneliner\\cmdgen.py\u001b[0m in \u001b[0;36mgetCmd\u001b[1;34m(self, authData, transportTarget, *varNames, **kwargs)\u001b[0m\n\u001b[0;32m 174\u001b[0m kwargs.get('contextName', null)),\n\u001b[0;32m 175\u001b[0m \u001b[1;33m*\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_null\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mx\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mvarNames\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 176\u001b[1;33m **kwargs):\n\u001b[0m\u001b[0;32m 177\u001b[0m \u001b[1;32mbreak\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 178\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0merrorIndication\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0merrorStatus\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0merrorIndex\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mvarBinds\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mC:\\Anaconda3\\lib\\site-packages\\pysnmp\\hlapi\\asyncore\\sync\\cmdgen.py\u001b[0m in \u001b[0;36mgetCmd\u001b[1;34m(snmpEngine, authData, transportTarget, contextData, *varBinds, **options)\u001b[0m\n\u001b[0;32m 92\u001b[0m \u001b[0mcontextData\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m*\u001b[0m\u001b[0mvarBinds\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 93\u001b[0m **dict(cbFun=cbFun, cbCtx=cbCtx,\n\u001b[1;32m---> 94\u001b[1;33m lookupMib=options.get('lookupMib', True)))\n\u001b[0m\u001b[0;32m 95\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 96\u001b[0m \u001b[0msnmpEngine\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtransportDispatcher\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrunDispatcher\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mC:\\Anaconda3\\lib\\site-packages\\pysnmp\\hlapi\\asyncore\\cmdgen.py\u001b[0m in \u001b[0;36mgetCmd\u001b[1;34m(snmpEngine, authData, transportTarget, contextData, *varBinds, **options)\u001b[0m\n\u001b[0;32m 119\u001b[0m \u001b[0msnmpEngine\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0maddrName\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcontextData\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcontextEngineId\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 120\u001b[0m \u001b[0mcontextData\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcontextName\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 121\u001b[1;33m \u001b[0mvbProcessor\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmakeVarBinds\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0msnmpEngine\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mvarBinds\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0m__cbFun\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 122\u001b[0m (options.get('lookupMib', True),\n\u001b[0;32m 123\u001b[0m options.get('cbFun'), options.get('cbCtx'))\n", + "\u001b[1;32mC:\\Anaconda3\\lib\\site-packages\\pysnmp\\hlapi\\varbinds.py\u001b[0m in \u001b[0;36mmakeVarBinds\u001b[1;34m(self, snmpEngine, varBinds)\u001b[0m\n\u001b[0;32m 23\u001b[0m \u001b[1;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mvarBind\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mObjectIdentity\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 24\u001b[0m \u001b[0mvarBind\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mObjectType\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0mvarBind\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 25\u001b[1;33m \u001b[1;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mvarBind\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtuple\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m \u001b[1;31m# legacy\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 26\u001b[0m \u001b[0mvarBind\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mObjectType\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mObjectIdentity\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mvarBind\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mvarBind\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m*\u001b[0m\u001b[0mvarBind\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mvarBind\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 27\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;31mIndexError\u001b[0m: string index out of range" + ] + } + ], + "source": [ + "results = snmpget( '1.3.6.1.4.1.674.10892.1.600.30.1.8.1.1', \\\n", + " '1.3.6.1.4.1.674.10892.1.600.30.1.8.1.3' )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we will modify the function definition to accept a variable number of arguments.\n", + "\n", + "The function getCmd() also uses this same technique. We can pass along these additional OIDs to the getCmd() function but we must prefix the more_oids variable with a asterisk `*`." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def snmpget(oid, *more_oids):\n", + " \n", + " from pysnmp.entity.rfc3413.oneliner import cmdgen\n", + " \n", + " global SNMP_HOST\n", + " global SNMP_PORT\n", + " global SNMP_COMMUNITY\n", + " \n", + " cmdGen = cmdgen.CommandGenerator()\n", + "\n", + " errorIndication, errorStatus, errorIndex, varBinds = cmdGen.getCmd(\n", + " cmdgen.CommunityData(SNMP_COMMUNITY),\n", + " cmdgen.UdpTransportTarget((SNMP_HOST, SNMP_PORT)),\n", + " oid,\n", + " *more_oids\n", + " )\n", + "\n", + " # Predefine our results list \n", + " results = []\n", + " \n", + " # Check for errors and print out results\n", + " if errorIndication:\n", + " print(errorIndication)\n", + " else:\n", + " if errorStatus:\n", + " print('%s at %s' % (\n", + " errorStatus.prettyPrint(),\n", + " errorIndex and varBinds[int(errorIndex)-1] or '?'\n", + " )\n", + " )\n", + " else:\n", + " for name, val in varBinds:\n", + " results.append( val )\n", + " \n", + " if len(results) == 1:\n", + " return results[0]\n", + " else:\n", + " return results\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now when we call snmpget() with any number of oids.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false, + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PS1 Current 1\n", + "PS2 Current 2\n", + "System Board Pwr Consumption\n", + "16\n", + "0\n", + "196\n", + "----------------\n", + "PS1 Current 1\n" + ] + } + ], + "source": [ + "# get 6 oid values in one call.\n", + "results = snmpget( '1.3.6.1.4.1.674.10892.1.600.30.1.8.1.1', \\\n", + " '1.3.6.1.4.1.674.10892.1.600.30.1.8.1.2', \\\n", + " '1.3.6.1.4.1.674.10892.1.600.30.1.8.1.3', \\\n", + " '1.3.6.1.4.1.674.10892.1.600.30.1.6.1.1', \\\n", + " '1.3.6.1.4.1.674.10892.1.600.30.1.6.1.2', \\\n", + " '1.3.6.1.4.1.674.10892.1.600.30.1.6.1.3', \\\n", + " )\n", + "\n", + "for ans in results:\n", + " print(ans)\n", + " \n", + "print('----------------')\n", + "\n", + "# get 1 oid value\n", + "result = snmpget( '1.3.6.1.4.1.674.10892.1.600.30.1.8.1.1' )\n", + "\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Our snmpget() function is rather functional but we are still referencing the global variables for host,port,community defined back at the top of this notebook.\n", + "\n", + "Lets make this code even more reusable by encapsulating everything into a `Class`" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "class SNMPClient:\n", + " # This is the SNMPClient constructor\n", + " def __init__(self, host, port=161, community='public'):\n", + " \n", + " self.host = host\n", + " self.port = port\n", + " self.community = community\n", + "\n", + " def snmpget(self, oid, *more_oids):\n", + "\n", + " from pysnmp.entity.rfc3413.oneliner import cmdgen\n", + "\n", + " cmdGen = cmdgen.CommandGenerator()\n", + "\n", + " \n", + " errorIndication, errorStatus, errorIndex, varBinds = cmdGen.getCmd(\n", + " cmdgen.CommunityData(self.community),\n", + " cmdgen.UdpTransportTarget((self.host, self.port)),\n", + " oid,\n", + " *more_oids\n", + " )\n", + "\n", + " # Predefine our results list \n", + " results = []\n", + "\n", + " # Check for errors and print out results\n", + " if errorIndication:\n", + " print(errorIndication)\n", + " else:\n", + " if errorStatus:\n", + " print('%s at %s' % (\n", + " errorStatus.prettyPrint(),\n", + " errorIndex and varBinds[int(errorIndex)-1] or '?'\n", + " )\n", + " )\n", + " else:\n", + " for name, val in varBinds:\n", + " results.append( val )\n", + "\n", + " if len(results) == 1:\n", + " return results[0]\n", + " else:\n", + " return results\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dell Inc.\n", + "PowerEdge R720\n", + "PS1 Current 1\n", + "PS2 Current 2\n", + "System Board Pwr Consumption\n", + "16\n", + "0\n", + "196\n" + ] + } + ], + "source": [ + "myClient = SNMPClient('192.168.1.60', 161, 'public')\n", + "\n", + "results = myClient.snmpget('1.3.6.1.4.1.674.10892.1.300.10.1.8.1', \\\n", + " '1.3.6.1.4.1.674.10892.1.300.10.1.9.1', \\\n", + " '1.3.6.1.4.1.674.10892.1.600.30.1.8.1.1', \\\n", + " '1.3.6.1.4.1.674.10892.1.600.30.1.8.1.2', \\\n", + " '1.3.6.1.4.1.674.10892.1.600.30.1.8.1.3', \\\n", + " '1.3.6.1.4.1.674.10892.1.600.30.1.6.1.1', \\\n", + " '1.3.6.1.4.1.674.10892.1.600.30.1.6.1.2', \\\n", + " '1.3.6.1.4.1.674.10892.1.600.30.1.6.1.3' )\n", + "\n", + "for ans in results:\n", + " print(ans)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that we have a working SNMP Client that we can use to query the server lets look at some of the interesting data presented by the Dell OpenManage SNMP extensions." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "\n", + "# Get the RU height of the server, this will return 1U for a R630, 2U for a R730, etc.\n", + "\n", + "\n", + "# Cooling Device AKA Fan Location Name\n", + "# 1.3.6.1.4.1.674.10892.1.700.12.1.8.1.1\n", + "\n", + "# Cooling Fan RPMs\n", + "# 1.3.6.1.4.1.674.10892.1.700.12.1.6.1.1\n", + "\n", + "# Cooling Fan Status (3 is OK)\n", + "# 1.3.6.1.4.1.674.10892.1.700.12.1.5.1.1\n", + "\n", + "# Cooling Unit Status (All Fans considers (3 is OK)\n", + "# 1.3.6.1.4.1.674.10892.1.700.10.1.8.1.1\n", + "\n", + "\n", + "# Temp Probe Location(s)\n", + "# 1.3.6.1.4.1.674.10892.1.700.20.1.8.1.1\n", + "# 1.3.6.1.4.1.674.10892.1.700.20.1.8.1.2\n", + "\n", + "# Temp Reading (Value is Celius 1/10 Degree)\n", + "# 1.3.6.1.4.1.674.10892.1.700.20.1.6.1.1\n", + "# 1.3.6.1.4.1.674.10892.1.700.20.1.6.1.2\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When we query the system's temperature probes tthe value is returned in celsius at a resolution of 1/10 of a degree.\n", + "\n", + "So a value of 234 is 23.4 celsius.\n", + "\n", + "To get this value we simple divide by 10.\n", + "\n", + "Additionally, I want the temperature reading in Fahrenheit so we use the formula to convert Celsius to Fahrenheit.\n", + "\n", + "T(F) = T(C) x 9/5 + 32\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "collapsed": false, + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "System Board Inlet Temp: 69F\n", + "System Board Exhaust Temp: 95F\n" + ] + } + ], + "source": [ + "myClient = SNMPClient('192.168.1.60', 161, 'public')\n", + "\n", + "results = myClient.snmpget('1.3.6.1.4.1.674.10892.1.700.20.1.8.1.1', \\\n", + " '1.3.6.1.4.1.674.10892.1.700.20.1.6.1.1', \\\n", + " '1.3.6.1.4.1.674.10892.1.700.20.1.8.1.2', \\\n", + " '1.3.6.1.4.1.674.10892.1.700.20.1.6.1.2')\n", + "\n", + "temp1 = results[1]\n", + "# Divide by 10\n", + "temp1_in_c = temp1 / 10\n", + "# Convert Celsius to Fahrenheit\n", + "temp1_in_f = temp1_in_c * (9/5) + 32\n", + "# Print the results\n", + "print(results[0] +\": \"+ str( temp1_in_f ) + 'F') \n", + "\n", + "\n", + "temp2 = results[3]\n", + "# Divide by 10\n", + "temp2_in_c = temp2 / 10\n", + "# Convert Celsius to Fahrenheit\n", + "temp2_in_f = temp2_in_c * (9/5) + 32\n", + "# Print the results\n", + "print(results[2] +\": \"+ str( temp2_in_f ) + 'F') " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "I hope you find this python example useful and educational. You are free to use the above code how you see fit.\n", + "\n", + "* More Python Tutorials - http://jcutrer.com/howto/dev/python/\n", + "* Question, Comments, Suggestions - http://jcutrer.com/howto/dev/python/python-tutorial-query-dell-poweredge-temperature-snmp-data\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.0" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/web/rss/How to Parse and Combine RSS News headlines using feedparser.ipynb b/web/rss/How to Parse and Combine RSS News headlines using feedparser.ipynb new file mode 100644 index 0000000..eb40f3d --- /dev/null +++ b/web/rss/How to Parse and Combine RSS News headlines using feedparser.ipynb @@ -0,0 +1,139 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This tutorial and IPython notebook can be found at \n", + "\n", + "http://jcutrer.com/howto/dev/python/python-tutorial-howto-parse-rss-headlines\n", + "\n", + "The feedparser package is required, install it with the following command.\n", + "\n", + "`pip install feedparser`" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import feedparser\n", + "\n", + "# Function to fetch the rss feed and return the parsed RSS\n", + "def parseRSS( rss_url ):\n", + " return feedparser.parse( rss_url ) \n", + " \n", + "# Function grabs the rss feed headlines (titles) and returns them as a list\n", + "def getHeadlines( rss_url ):\n", + " headlines = []\n", + " \n", + " feed = parseRSS( rss_url )\n", + " for newsitem in feed['items']:\n", + " headlines.append(newsitem['title'])\n", + " \n", + " return headlines" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "collapsed": false, + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "France bombs Islamic State HQ, hunts attacker who got away\n", + "Clinton campaign defends debate 9/11 remarks\n", + "Donald Trump: ‘O’Malley is a clown’; ‘Hillary is owned by Wall Street’\n", + "College student from California studying abroad killed in Paris attacks\n", + "About 1,500 Mormons resign from church in protest of same-sex policy\n", + "Pentagon says five Guantanamo detainees transferred to United Arab Emirates\n", + "Paris attacks: Video shows firefight outside Bataclan\n", + "Paris attacks show U.S. surveillance of Islamic State may be ‘going dark’\n", + "Belgian connection: At least 3 held in Brussels over Paris attacks\n", + "Clinton wobbled on foreign policy in debate\n", + "Clinton cites 9/11 in defending Wall Street donations\n", + "Sanders scores applause for Eisenhower quip\n", + "Sanders campaign claims victory in CBS dispute\n", + "Paris attacks may lead to US military anti-IS escalation\n", + "Sanders aide pushes back against CBS switch to foreign policy focus for debate\n", + "Five questions about Paris for Clinton, Sanders, and O’Malley\n", + "France Strikes ISIS Targets in Syria in Retaliation for Attacks - New York Times\n", + "Clinton's debate performance leaves trail of fodder for political adversaries - Washington Post\n", + "Parisians united: What the attacks mean to us - CNN\n", + "In wake of attacks, presidential contenders focus on Syrian refugees - Miami Herald\n", + "The Belgian neighborhood indelibly linked to jihad - Washington Post\n", + "Americans pay respects to Paris terror victims - USA TODAY\n", + "Pentagon transfers 5 Yemenis being held at Guantanamo Bay to UAE - Washington Post\n", + "Paris unites in defiant solidarity, then scatters in panic - Washington Post\n", + "Paris terror attack: Names of victims start to emerge - CNN\n", + "Patriots still undefeated after late field goal - NFL.com\n" + ] + } + ], + "source": [ + "# A list to hold all headlines\n", + "allheadlines = []\n", + "\n", + "# List of RSS feeds that we will fetch and combine\n", + "newsurls = {\n", + " 'apnews': 'http://hosted2.ap.org/atom/APDEFAULT/3d281c11a76b4ad082fe88aa0db04909',\n", + " 'googlenews': 'http://news.google.com/?output=rss',\n", + " 'yahoonews': 'http://news.yahoo.com/rss/'\n", + "}\n", + "\n", + "# Iterate over the feed urls\n", + "for key,url in newsurls.items():\n", + " # Call getHeadlines() and combine the returned headlines with allheadlines\n", + " allheadlines.extend( getHeadlines( url ) )\n", + "\n", + "\n", + "# Iterate over the allheadlines list and print each headline\n", + "for hl in allheadlines:\n", + " print(hl)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "I hope you find this python example useful and educational. You are free to use the above code how you see fit. I do however suggest that you implement some type of rss feed caching as some services may block your ip for excessive requests.\n", + "\n", + "More Python Tutorials - http://jcutrer.com/howto/dev/python/\n", + "\n", + "Question, Comments, Suggestions - http://jcutrer.com/howto/dev/python/python-tutorial-howto-parse-rss-headlines\n", + " \n", + " " + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.0" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +}