28 |
import sys |
import sys |
29 |
import os |
import os |
30 |
import time |
import time |
31 |
|
import signal |
32 |
|
|
33 |
spindown_cmd = "" |
spindown_cmd = "" |
34 |
spindown_cmd_args = "" |
spindown_cmd_args = "" |
35 |
|
keep_running = True |
36 |
|
signals = {} |
37 |
|
|
38 |
|
class Error(Exception): |
39 |
|
pass |
40 |
|
|
41 |
|
|
42 |
|
def signal_handler(signal, stack): |
43 |
|
global keep_running |
44 |
|
keep_running = False |
45 |
|
|
46 |
|
|
47 |
|
def getsignals(): |
48 |
|
signals = {} |
49 |
|
for name in dir(signal): |
50 |
|
if name.startswith("SIG"): |
51 |
|
signals[getattr(signal, name)] = name |
52 |
|
return signals |
53 |
|
|
|
# |
|
|
# Disk, how long to wait for, last msio value, spun down |
|
|
# |
|
54 |
|
|
55 |
def search_path(filename, search_path): |
def search_path(filename, search_path): |
56 |
file_found = False |
file_found = False |
69 |
if options.debug: |
if options.debug: |
70 |
print "%s: %s" % (time.asctime(time.localtime()), message) |
print "%s: %s" % (time.asctime(time.localtime()), message) |
71 |
|
|
72 |
|
|
73 |
|
def log(message): |
74 |
|
pass |
75 |
|
|
76 |
|
|
77 |
def load_config(options): |
def load_config(options): |
78 |
global spindown_cmd, spindown_cmd_args |
global spindown_cmd, spindown_cmd_args |
79 |
cf = ConfigParser.SafeConfigParser() |
cf = ConfigParser.SafeConfigParser() |
83 |
except IOError, e: |
except IOError, e: |
84 |
print "Got a '%s' trying to read %s" % (e.strerror, options.config) |
print "Got a '%s' trying to read %s" % (e.strerror, options.config) |
85 |
sys.exit(1) |
sys.exit(1) |
86 |
|
except ConfigParser.MissingSectionHeaderError, e: |
87 |
|
print "Parser error: '%s'" % (e.message) |
88 |
|
sys.exit(1) |
89 |
if cf.has_option("DEFAULT", "wait"): |
if cf.has_option("DEFAULT", "wait"): |
90 |
defaultwait = cf.get("DEFAULT", "wait") |
defaultwait = cf.get("DEFAULT", "wait") |
91 |
else: |
else: |
132 |
|
|
133 |
|
|
134 |
def monitor_disks(config, options): |
def monitor_disks(config, options): |
135 |
|
global keep_running |
136 |
debug(options, "Monitoring disks") |
debug(options, "Monitoring disks") |
137 |
while True: |
while keep_running: |
138 |
for disk in config: |
for disk in config: |
139 |
debug(options, "Considering %s" % (disk)) |
debug(options, "Considering %s" % (disk)) |
140 |
ds = diskstats.DiskStats(disk) |
ds = diskstats.DiskStats(disk) |
153 |
if msio == config[disk]["last_msio"]: |
if msio == config[disk]["last_msio"]: |
154 |
debug(options, "Disk has been idle since last considered") |
debug(options, "Disk has been idle since last considered") |
155 |
now = int(time.time()) |
now = int(time.time()) |
156 |
if (now - config[disk]["timestamp"]) >= config[disk]["wait"]: |
if (now - config[disk]["timestamp"]) >= int(config[disk]["wait"]): |
157 |
debug(options, "Disk eligible for spinning down") |
debug(options, "Disk eligible for spinning down") |
158 |
# We can spin this disk down |
# We can spin this disk down |
159 |
if not config[disk]["spun_down"]: |
if not config[disk]["spun_down"]: |
160 |
if spin_down(disk): |
if spin_down(options, disk): |
161 |
debug(options, "Disk spun down") |
debug(options, "Disk spun down") |
162 |
config[disk]["spun_down"] = True |
config[disk]["spun_down"] = True |
163 |
else: |
else: |
167 |
else: |
else: |
168 |
# This disk is ineligible for spinning down at this time |
# This disk is ineligible for spinning down at this time |
169 |
debug(options, "Disk idle for %s seconds, but not for long enough (%s)" % (now - config[disk]["timestamp"], config[disk]["wait"])) |
debug(options, "Disk idle for %s seconds, but not for long enough (%s)" % (now - config[disk]["timestamp"], config[disk]["wait"])) |
|
#config[disk]["timestamp"] = int(time.time()) |
|
170 |
else: |
else: |
|
debug(options, "Disk not idle (old msio: %s, current msio: %s)" % (config[disk]["last_msio"], msio)) |
|
171 |
config[disk]["last_msio"] = msio |
config[disk]["last_msio"] = msio |
172 |
config[disk]["timestamp"] = int(time.time()) |
config[disk]["timestamp"] = int(time.time()) |
173 |
config[disk]["spun_down"] = False |
if config[disk]["spun_down"]: |
174 |
|
debug(options, "%s presumed spun back up by activity" % (disk)) |
175 |
|
config[disk]["spun_down"] = False |
176 |
|
debug(options, "Disk not idle (old msio: %s, current msio: %s)" % (config[disk]["last_msio"], msio)) |
177 |
debug(options, "Sleeping") |
debug(options, "Sleeping") |
178 |
time.sleep(60) |
time.sleep(60) |
179 |
|
debug(options, "Shutting down") |
180 |
|
|
181 |
def main(): |
def main(): |
182 |
|
global options |
183 |
|
global signals |
184 |
|
signals = getsignals() |
185 |
|
signal.signal(signal.SIGTERM, signal_handler) |
186 |
|
signal.signal(signal.SIGINT, signal_handler) |
187 |
parser = optparse.OptionParser() |
parser = optparse.OptionParser() |
188 |
parser.add_option("-n", "--dry-run", |
parser.add_option("-n", "--dry-run", |
189 |
action="store_true", |
action="store_true", |