#! /usr/local/bin/python
# to be run on the node that is to have its hard disks spun down and up

import os, string, sys, time
import isi.app.lib.procs as procs


def printUsage():
	print 'Usage:' 
	print '       %s <cycle-count>' % sys.argv[0]
	print '\nTo print this message: '
	print '       %s -h' % sys.argv[0]
	print '       %s --help' % sys.argv[0]

class ArgErr:
	def __init__(self, msg):
		self.msg = msg
		
try:
	if len(sys.argv) != 2:
		raise ArgErr('Too many or too few args given')

	if sys.argv[1] == "-h" or sys.argv[1] == "--help":
		printUsage()
		sys.exit(0)

	loopCount = int(sys.argv[1])
	if loopCount < 1:
		raise ValueErr("Arg value must be >= 1")
		
except ValueErr, err:
	print('ERROR: %s' % err.msg)
	printUsage()
	sys.exit(-1)
except ArgErr, err:
	print('ERROR: %s' % err.msg)
	printUsage()
	sys.exit(-1)
except SystemExit:
	sys.exit(0)
except:
	print('Unexpected error.')
	printUsage()
	sys.exit(-1)
	
	
## begin actual spinning up and down of disks
(error, host) = procs.get_cmd_output('/bin/hostname -s')
if error or len(host) <= 0:
	print 'unable to get hostname with /bin/hostname.  exiting.'
	sys.exit(-1)
	
dstDir = time.strftime("%Y-%m-%d_%H:%M", 
		time.localtime()) + '_' + host[0] + '_spintest'

if not os.path.isdir(dstDir):
	os.mkdir(dstDir)
else:
	print 'Destination directory ', dstDir, ' already exists.\n'
	print 'Remove or rename directory before rerunning %s.' % sys.argv[0]
	sys.exit(0)
	
os.chdir(dstDir)
procs.get_cmd_output('/usr/bin/isi_radish -ga > radish_spin_' + host[0] + '_begin')

loopNum = 0

while loopNum < loopCount:
	## provide periodic progress updates and a way to gauge the rate of
	## spinning down and back up
	if loopNum % 100 == 0:
		procs.get_cmd_output('echo completed %d' % loopNum);
		procs.get_cmd_output('/usr/bin/touch spinmark.%d' % loopNum)

	procs.get_cmd_output('/usr/bin/isi_radish -svv')

	## the spin-down returns instantly, but I doubt the disk has really
	## stopped spinning.  We want the worst spin-up times, which means we
	## really want the disks to stop.  So let's give them a few seconds to
	## settle.  Maxtor says drives need 8.8 seconds to spin down.  To be
	## safe, just make it 10.
	procs.get_cmd_output('/bin/sleep 10')
	
	## spinup will wait 4-5 seconds, and tweconfig serializes it, so it
	## takes ~35 seconds to spin up all disks.  Ouch.  I tried:
	##  - parallel tweconfig's, one per drive.  Doesn't seem to actually
	##    parallelize the accesses at all!
	##  - parallel reads, one per drive -- helps, but occasionally [more
	##    often with the sleep 5, so probably if the drive is fully spun 
	##    down] gets a 0x50 from the drive and triggers a twe_reset()
	
	## It seems the twe_reset actually spins up all the drives, so why
	## beat around the bush!  This occasionally causes a software watchdog
	## warning, but with no harmful effects.  This is still slower than
	## it need be, but takes ~15 secs instead of ~35.  You can comment out
	## this one 'tweconfig -R' line for the safer but slower run.
	(error, output) = procs.get_cmd_output('/usr/bin/isi_tweconfig -R')
	(error, output) = procs.get_cmd_output('/usr/bin/isi_radish -ivv')
	
	loopNum += 1

procs.get_cmd_output('/usr/bin/isi_radish -ga > radish_spin_' + host[0] + '_end')




