I wrote this simple Munin plugin to graph average fan speed and I want to redo it to OOP - strictly as a learning exercise. Don't have a clue where to start though. Anyone feel like offering some guidance or even an example of what this script should look like when done. I will use it to redo some other scripts into an OOP style as well; again for learning purposes.
import sys
import subprocess
CMD = "/usr/sbin/omreport chassis fans".split()
# Munin populates sys.argv[1] with "" (an empty argument), lets remove it.
sys.argv = [x for x in sys.argv if x]
if len(sys.argv) > 1:
if sys.argv[1].lower() == "autoconfig":
print "autoconfig"
elif sys.argv[1].lower() == "config":
print "graph_title Average Fan Speed"
print "graph_args --base 1000 -l 0"
print "graph_vlabel speed (RPM)"
print "graph_category Chassis"
print "graph_info This graph shows the average speed of all fans"
print "graph_period second"
print "speed.label speed"
print "speed.info Average fan speed for the five minutes."
else:
try:
data = subprocess.Popen(CMD,stdout=subprocess.PIPE).stdout.readlines()
except OSError, e:
print >> sys.stderr, "Error running '%s', %s" % (" ".join(cmd), e)
sys.exit(1)
count = total = 0
for item in data:
if "Reading" in item:
# Extract variable length fan speed, without regex.
total += int(item.split(":")[1].split()[0])
count += 1
# Sometimes omreport returns zero output if omsa services aren't started.
if not count or not total:
print >> sys.stderr, 'Error: "omreport chassis fans" returned 0 output.'
print >> sys.stderr, 'OMSA running? Try: "srvadmin-services.sh status".'
sys.exit(1)
avg = (total / count)
print "speed.value %s" % avg
You remake it in OOP by identifying code and data that goes together. These you then merge into "classes".
You actual data above seems to be the output of a process.
The code is iterating over it. I guess you can make a class out of that if you want to, but it's a bit silly. :)
So, something like this (obviously completely untested code):
import sys
import subprocess
class Fanspeed(object):
def __init__(self, command):
self.command = command.split()
def average_fan_speed(self):
data = subprocess.Popen(CMD,stdout=subprocess.PIPE).stdout.readlines()
count = total = 0
for item in data:
if "Reading" in item:
# Extract variable length fan speed, without regex.
total += int(item.split(":")[1].split()[0])
count += 1
# Sometimes omreport returns zero output if omsa services aren't started.
if not count or not total:
raise ValueError("I found no fans. Is OMSA services started?"
avg = (total / count)
return % avg
if __main__ == '__main__':
# Munin populates sys.argv[1] with "" (an empty argument), lets remove it.
sys.argv = [x for x in sys.argv if x]
if len(sys.argv) > 1:
if sys.argv[1].lower() == "autoconfig":
print "autoconfig"
elif sys.argv[1].lower() == "config":
print "graph_title Average Fan Speed"
print "graph_args --base 1000 -l 0"
print "graph_vlabel speed (RPM)"
print "graph_category Chassis"
print "graph_info This graph shows the average speed of all fans"
print "graph_period second"
print "speed.label speed"
print "speed.info Average fan speed for the five minutes."
else:
try:
cmd = "/usr/sbin/omreport chassis fans"
fanspeed = Fanspeed(cmd)
average = fanspeed.average_fan_speed()
except OSError, e:
print >> sys.stderr, "Error running '%s', %s" % (cmd, e)
sys.exit(1)
except ValueError, e:
# Sometimes omreport returns zero output if omsa services aren't started.
print >> sys.stderr, 'Error: "omreport chassis fans" returned 0 output.'
print >> sys.stderr, 'OMSA running? Try: "srvadmin-services.sh status".'
sys.exit(1)
But YMMV. It's perhaps a bit clearer.
Related
I've been struggling with this program for some time.
I wrote this program to learn how to run the same program in different CPU's at the same time and to reduce processing time.
By itself, the program is not complex, just detect if there are some screenshots in different directories, but as I said before my final goal is not to detect those files, but to learn multiprocessing.
To be easier to test, instead of reading files or reading user inputs, I just set those variables so you won't have to be typing those things. I'll be faster to test this way.
Here's the code:
from multiprocessing import Array, Lock, Pool
def DetectSCREENSHOT(file, counter, total):
# To check if this function is ever accessed
print 'Entered in DetectSCREENSHOT function'
if file.startswith('Screenshot') == False:
print ' (%s %%) ERROR: the image is not a screenshot ' %(round((float(counter)/total)*100, 1))
return 0
else:
print ' (%s %%) SUCCESS: the image is a screenshot' %(round((float(counter)/total)*100, 1))
return 1
def DetectPNG(file_list, counter_success_errors, lock):
# To check if this function is ever accessed
print 'Entered in DetectPNG function'
for i in range(len(file_list)):
file = file_list[i]
# If the file is an .png image:
if file.endswith('.png'):
lock.acquire()
counter_success_errors[0] = counter_success_errors[0] + 1
lock.release()
if DetectSCREENSHOT(file, counter_success_errors[0], len(file_list)) == 1:
lock.acquire()
counter_success_errors[1] = counter_success_errors[1] + 1
lock.release()
else:
lock.acquire()
counter_success_errors[2] = counter_success_errors[2] + 1
lock.release()
def Main():
# file_list = # List of lists of files in different directories
file_list = [['A.png', 'B.png', 'C.txt', 'Screenshot_1.png'], ['D.txt', 'Screenshot_2.png', 'F.png', 'Screenshot_3.png']]
# Array where the first cell is a counter, the second one, the number of successes and the third one, the number of errors.
counter_success_errors = Array('i', 3)
lock = Lock()
counter_success_errors[0] = 0
counter_success_errors[1] = 0
counter_success_errors[2] = 0
# Number of CPUS's to be used (will set the number of different processes to be run)
# CPUs = raw_input('Number of CPUs >> ')
CPUs = 2
pool = Pool(processes=CPUs)
for i in range(CPUs):
pool.apply_async(DetectPNG, [file_list[i], counter_success_errors, lock])
pool.close()
pool.join()
success = int(counter_success_errors[1])
errors = int(counter_success_errors[2])
print(' %s %s %s successfully. %s %s.' %('Detected', success, 'screenshot' if success == 1 else 'screenshots', errors, 'error' if errors == 1 else 'errors'))
#################################################
if __name__ == "__main__":
Main()
When I execute it, I don't get any errors, but it looks like it doesn't even access to both DetectPNG and DetectSCREENSHOT functions.
What's broken in the code?
Output: Detected 0 screenshots successfully. 0 errors.
for i in range(0, 650):
s = ticket[i]
try:
response = resource.get(path='ticket/%s' % s[0]) # Get ticket data from RT server
except urllib2.URLError, e: # If connection fails
resource = RTResource(url, user, pwd, CookieAuthenticator) # Reconnect to RT server
count -= 1 # Count re-connection attempts
if count < 0:
print "Connection failed at ticket %s" % s[0]
print "Got %s tickets out of %s" % {i + 1, len(ticket) + 1}
wb.save(fname)
sys.exit(1)
print 'Trying again...'
i -= 1
continue
count = 10
...more code here...
The above code executes well but will skip an iteration when exception is thrown. I am trying to decreament the value of i and then continuing the loop so that when exception is thrown, the loop will repeat for same value of i. When a value of i is skipped I lose one ticket from RT server. How do I fix it?
You ... can't do that in python. You can't affect the value of the iterator - it's using it's own internal value for each step in the loop, not paying attention to your attempts to override. If you have to succeed for each iteration I use something like this:
while True:
# code here
if success:
break
And place that inside your for loop. Or better, extract a method to simplify readability, but that's another post.
(Besides the correct point raised by g.d.d.c. about the inability to decrement the loop counter the specific way you've gone, )this sort of stuff is exactly the motivation for finally. You should probably organize your code as follows:
try - the part that's supposed to run but might not
except - the part to do only if there was a problem
else (optional) - the part to do only if there wasn't a problem
finally - stuff to do in any case
An alternative to embedding a while loop in your for loop, as suggested by g.d.d.c, is to simply use a while loop instead of a for loop, like so:
i = 0
while i < 650:
s = ticket[i]
try:
response = resource.get(path='ticket/%s' % s[0]) # Get ticket data from RT server
except urllib2.URLError, e: # If connection fails
resource = RTResource(url, user, pwd, CookieAuthenticator) # Reconnect to RT server
count -= 1 # Count re-connection attempts
if count < 0:
print "Connection failed at ticket %s" % s[0]
print "Got %s tickets out of %s" % {i + 1, len(ticket) + 1}
wb.save(fname)
sys.exit(1)
print 'Trying again...'
continue
count = 10
i += 1
...more code here...
from brisa.core.reactors import install_default_reactor
reactor = install_default_reactor()
print reactor
from brisa.core.threaded_call import run_async_function
from brisa.upnp.control_point.control_point import ControlPoint
from datetime import datetime
service = ('u', 'urn:schemas-upnp-org:service:SwitchPower:1')
binary_light_type = 'urn:schemas-upnp-org:device:BinaryLight:1'
def on_new_device(dev):
print 'Got new device:', dev.udn
print "Type 'list' to see the whole list"
if not dev:
return
def get_switch_service(device):
return device.services[service[1]]
def create_control_point():
c = ControlPoint()
print "hello"
c.subscribe('new_device_event', on_new_device)
print "c"
return c
def main():
""" Main loop iteration receiving input commands.
"""
print "hell"
c = create_control_point()
print "helllo"
c.start()
run_async_function(_handle_cmds, (c, ))
reactor.add_after_stop_func(c.stop)
reactor.main()
def _exit(c):
""" Stops the _handle_cmds loop
"""
global running_handle_cmds
running_handle_cmds = False
def _search(c):
""" Start searching for devices of type upnp:rootdevice and repeat
search every 600 seconds (UPnP default)
"""
c.start_search(600, 'upnp:rootdevice')
def _get_status(c):
""" Gets the binary light status and print if it's on or off.
"""
try:
service = get_switch_service(c.current_server)
status_response = service.GetStatus()
if status_response['ResultStatus'] == '1':
print 'Binary light status is on'
else:
print 'Binary light status is off'
except Exception, e:
if not hasattr(c, 'current_server') or not c.current_server:
print 'BinaryLight device not set.Please use set_light <n>'
else:
print 'Error in get_status():', e
def _get_target(c):
""" Gets the binary light target and print if it's on or off.
"""
try:
service = get_switch_service(c.current_server)
status_response = service.GetTarget()
if status_response['RetTargetValue'] == '1':
print 'Binary light target is on'
else:
print 'Binary light target is off'
except Exception, e:
if not hasattr(c, 'current_server') or not c.current_server:
print 'BinaryLight device not set.Please use set_light <n>'
else:
print 'Error in get_target():', e
def _stop(c):
""" Stop searching
"""
c.stop_search()
def _list_devices(c):
""" Lists the devices that are in network.
"""
k = 0
for d in c.get_devices().values():
print 'Device no.:', k
print 'UDN:', d.udn
print 'Name:', d.friendly_name
print 'Device type:', d.device_type
print 'Services:', d.services.keys() # Only print services name
print
k += 1
if __name__ == '__main__':
print "hello"
main()
I am getting the output:
ankit#ubuntu:~/Desktop$ python controlpt.py
<brisa.core.reactors.glib2.GLib2Reactor object at 0x88c3e0c>
hello
hell
It is not going to the line c = create_control_point. why is that? please guide me in removing this error.
I am not familiar with this 'brisa' library. I would gather that, for some reason, the ControlPoint constructor is exiting the entire program using sys.exit() (or is calling some equivalent C code).
Run the program on the command-line, like this:
$ python
>>> import controlpt
>>> controlpt.main()
Then you should be able to see if it is actually quitting the whole process. If it dumps you back to the >>> prompt, then I don't know what's going on. But if it quits Python entirely, it means that that ControlPoint constructor is quitting.
The error is given at the end:
from brisa.core.reactors import install_default_reactor
reactor = install_default_reactor()
print reactor
from brisa.upnp.control_point.control_point import ControlPoint
def on_new_device(dev):
print 'Got new device:', dev.udn
print "Type 'list' to see the whole list"
if not dev:
return
def create_control_point():
c = ControlPoint()
print "hello"
c.subscribe('new_device_event', on_new_device)
print "c"
return c
def main():
print "Inside main"
c = create_control_point()
print "Inside create control point"
c.start()
reactor.add_after_stop_func(c.stop)
reactor.main()
def _search(c):
""" Start searching for devices of type upnp:rootdevice and repeat
search every 600 seconds (UPnP default)
"""
c.start_search(600, 'upnp:rootdevice')
def _stop(c):
""" Stop searching
"""
c.stop_search()
def _list_devices(c):
""" Lists the devices that are in network.
"""
k = 0
for d in c.get_devices().values():
print 'Device no.:', k
print 'UDN:', d.udn
print 'Name:', d.friendly_name
print 'Device type:', d.device_type
print 'Services:', d.services.keys() # Only print services name
print
k += 1
# Control the loop at _handle_cmds function
running_handle_cmds = True
commands = {
'search': _search,
'stop': _stop,
'list': _list_devices,
}
def _handle_cmds(c):
while running_handle_cmds:
try:
input = raw_input('>>> ').strip()
if len(input.split(" ")) > 0:
try:
if len(input.split(" ")) > 1:
commands[input.split(" ")[0]](c, input.split(" ")[1])
else:
commands[input.split(" ")[0]](c)
except KeyError, IndexError:
print 'Invalid command, try help'
except TypeError:
print 'Wrong usage, try help to see'
except KeyboardInterrupt, EOFError:
c.stop()
break
# Stops the main loop
reactor.main_quit()
if __name__ == '__main__':
print "hello"
main()
Error:
ankit#ubuntu:~/Desktop$ python controlpt.py
<brisa.core.reactors.glib2.GLib2Reactor object at 0x965bdcc>
hello
Inside main
After that I know understand, it is not initialising the control point. The Information about the libraries(Control point) is available at http://brisa.garage.maemo.org/apidoc/index.html
If this is anything like some other event-based libraries such as Twisted, you want to get the reactor's main running before you do much of anything else.
Drop the call to reactor.main in your main function. Then, instead of just calling main in your if at the bottom, do this:
if __name__ == "__main__":
run_async_function(main)
reactor.main()
See if things behave more like what you expect then.
(run_async_function is in the threaded_call module.)
I want to do something like this:
try:
pid = int(file(lock_file, "r").read())
print "%s exists with pid: %s" % (lock_file, pid)
if not check_pid(pid):
print "%s not running. Phantom lock file? Continuing anyways" % pid
elif wall_time(pid) > 60 * 5:
print "%s has been running for more than 5 minutes. Killing it" % pid
os.kill(pid)
else:
print "Exiting"
sys.exit()
except IOError:
pass
lock = file(lock_file, "w")
lock.write("%s" % os.getpid())
lock.close()
How do I implement wall_time? Do I have to read from /proc or is there a better way?
Perhaps you could look at the creation time of the lock file. This wouldn't be guaranteed correct, but it would be correct in most cases (and the consequences of getting it wrong are minimal).
If you do not want to use the modify time of the lockfile for some reason, you could just write it down in the file:
pid, start_time = map(int, file(lock_file, "r").read().split())
...
lock.write("%s %d" % (os.getpid(), time.time()))