#!/usr/bin/python # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # # Sun Storage 7000 size calculator version 2009.Q3 # # Note that this script is unsupported, and makes use of unsupported XML-RPC # interfaces. # # For more information, check this blog post: # http://blogs.sun.com/ahl/entry/sun_storage_7410_space_calculator # import xmlrpclib import re import sys from copy import deepcopy help = 'After the jbod count, additional configuration for each JBOD can ' + \ 'be specified\nin the following form:\n\n' + \ '\th\tThe JBOD is only half populated\n' + \ '\tt\tThe JBOD is a 7210 Controller or J4500 Expansion\n' + \ '\t\tThe JBOD has logzilla devices\n\n' + \ 'For example, specifying "4 2 h1" will have 4 JBODs total, the first with ' + \ 'two\nlogzilla devices, and the second only a half JBOD with one ' + \ 'logzilla.\n\n' + \ 'specifying "size 500G t2 t1 t" will have a 7210 2 J4500s, using 500G disks' + \ ' the \nfirst with two logzilla devices, the second with one logzilla,' + \ ' and the last \nwithout any.\n\n' + \ 'The "add" keyword starts a new jbod count, and models the total ' + \ 'available size\nas if the JBODs were added to the config. Multiple ' + \ '"add" keywords are accepted.\n\n' + \ 'Displays available configurations with raw capacity in TB\n' + \ '(1000^4 = 1,000,000,000,000 bytes) and usable capacity in TiB\n' + \ '(1024^4 = 1,099,511,627,776 bytes).' htmlOutput = False diskSize = 1000 progname = sys.argv[0] del sys.argv[0] if len(sys.argv) != 0: if sys.argv[0] == "-w": htmlOutput = True; del sys.argv[0] def usage(): if htmlOutput: print '
'
	print 'usage: ' + progname + \
	    '   [size <#G|T>]'
	print '\t  [jbod layout] [add ...]\n'
	print help
	if htmlOutput:
		print '
' sys.exit(2) if htmlOutput: print '

Sun Storage 7000 Size Calculator Version 2009.Q3

' else: print 'Sun Storage 7000 Size Calculator Version 2009.Q3' if len(sys.argv) < 3: usage() server = xmlrpclib.ServerProxy('https://' + sys.argv[0] + ':215/ak') del sys.argv[0] password = sys.argv[0] del sys.argv[0] mirror = { 'type': 'mirror', 'disktype': 'data', 'modelOnly': True, 'nspf': False } mirror_n = { 'type': 'mirror', 'disktype': 'data', 'modelOnly': True, 'nspf': True } mirror3 = { 'type': 'mirror3', 'disktype': 'data', 'modelOnly': True, 'nspf': False } mirror3_n = { 'type': 'mirror3', 'disktype': 'data', 'modelOnly': True, 'nspf': True } raidz1 = { 'type': 'raidz1', 'disktype': 'data', 'modelOnly': True, 'nspf': False } raidz1_n = { 'type': 'raidz1', 'disktype': 'data', 'modelOnly': True, 'nspf': True } raidz2 = { 'type': 'raidz2', 'disktype': 'data', 'modelOnly': True, 'nspf': False } raidz2_n = { 'type': 'raidz2', 'disktype': 'data', 'modelOnly': True, 'nspf': True } raidz2_wide = { 'type': 'raidz2', 'maximize': True, 'disktype': 'data', 'modelOnly': True, 'nspf': False } raidz2_n_wide = { 'type': 'raidz2', 'maximize': True, 'disktype': 'data', 'modelOnly': True, 'nspf': True } raidz3_wide = { 'type': 'raidz3', 'maximize': True, 'disktype': 'data', 'modelOnly': True, 'nspf': False } raidz3_n_wide = { 'type': 'raidz3', 'maximize': True, 'disktype': 'data', 'modelOnly': True, 'nspf': True } stripe = { 'type': 'stripe', 'disktype': 'data', 'modelOnly': True } options = [ raidz2, raidz2_n, raidz2_wide, raidz2_n_wide, raidz3_wide, \ raidz3_n_wide, mirror, mirror_n, mirror3, mirror3_n, stripe, raidz1, \ raidz1_n ] jbod = { 'akch_disk': [] } for n in xrange(0, 24): jbod['akch_disk'].append({ 'akch_type': 'data', 'akch_size': diskSize, 'akch_device': 'none', 'akch_faulted': False, 'akch_present': True, }) configs = {} first = True while len(sys.argv) > 0: config = { 'akch_chassis': [] } ndrives = 0; if sys.argv[0] == "size": del sys.argv[0] newSize = sys.argv[0] del sys.argv[0] p = re.compile('([0-9]*)([G,T]?)') m = p.match(newSize) diskSize=int(m.group(1)) if m.group(2) == 'T': diskSize *= 1000; else: diskSize = 1000 for n in xrange(0,24): jbod['akch_disk'][n]['akch_size'] = diskSize njbods = int(sys.argv[0]) del sys.argv[0] for n in xrange(0, njbods): config['akch_chassis'].append(deepcopy(jbod)) ndrives += 24 idx = 0 while len(sys.argv) > 0 and sys.argv[0] != 'add': mod = sys.argv[0] del sys.argv[0] p = re.compile('(h?)(t?)([0-9]*)') m = p.match(mod) if m.group(1) == 'h': #print 'jbod %d = half'%(idx) for n in xrange(12, 24): config['akch_chassis'][idx]['akch_disk'] \ [n]['akch_present'] = False ndrives -= 12 if m.group(2) == 't': if first == True and idx == 0: for n in xrange(0, 2): #print 'jbod %d, disk %d = system'%(idx, n) config['akch_chassis'][idx]['akch_disk'] \ [n]['akch_type'] = 'system' ndrives -= 2 for n in xrange(24, 48): config['akch_chassis'][idx]['akch_disk'] \ .append({ 'akch_type': 'data', 'akch_size': diskSize, 'akch_device': 'none', 'akch_faulted': False, 'akch_present': True, }) ndrives += 24 if m.group(3): firstLog = 0 if first == True and idx == 0: firstLog = 2 for i in xrange(firstLog, firstLog + int(m.group(3))): #print 'jbod %d, disk %d = log'%(idx, i) config['akch_chassis'][idx]['akch_disk'][i] \ ['akch_type'] = 'log' ndrives -= 1 idx += 1 args = [ { 'methodName': 'system.login', 'params': [ { 'username': 'root', 'password': password } ] }, { 'methodName': 'system.push', 'params': [ config ] } ] for i in xrange(0, len(options)): args.append({ 'methodName': 'storage.poolConfig', 'methodParams': [ { 'quote': options[i] }, { 'peek': [] } ] }) args.append({ 'methodName': 'system.logout', 'params': [] }) result = server.system.multicall(args) del result[0] del result[0] result.pop() for c in configs: configs[c]['valid'] = False for i in xrange(0, len(result)): if isinstance(result[i], type([])): nspf = False if options[i].has_key('nspf'): nspf = options[i]['nspf'] name = options[i]['type'] if options[i].has_key('maximize'): name = name + ' wide' id = name if nspf: id = name + ' nspf' if not configs.has_key(id): if not first: continue configs[id] = { 'nspares': 0, 'ndata': 0, 'capacity': 0, 'adjusted': 0, 'minwidth': 100000, 'maxwidth': 0 } c = configs[id] r = result[i][0]['configurations'][0] # # Calculate the total usable capacity in Tebibytes # (binary). # adjusted = (r['capacity'] / 1000 ) * (1000.0/1024.0) \ ** 4 * 63.0 / 64.0 c['name'] = name c['nspf'] = nspf if r['width'] > c['maxwidth']: c['maxwidth'] = r['width'] if r['width'] < c['minwidth']: c['minwidth'] = r['width'] c['nspares'] += r['nspares'] c['ndata'] += ndrives - r['nspares'] c['capacity'] += r['capacity'] / 1000 c['adjusted'] += adjusted c['valid'] = True first = False; if len(sys.argv) > 0: assert sys.argv[0] == 'add' del sys.argv[0] if htmlOutput: print '' + \ '' + \ '' else: sys.stdout.write("\033[1m%-11s%7s%7s%7s%13s%15s%15s\033[0;0m\n" % ('type', 'NSPF', 'width', 'spares', 'data drives', 'raw (TB)', 'usable (TiB)')) ids = configs.keys() ids.sort() for id in ids: c = configs[id] if not c['valid']: continue if c['minwidth'] == c['maxwidth']: width = "%d"%(c['minwidth']) else: width = "%d-%d"%(c['minwidth'], c['maxwidth']) if htmlOutput: sys.stdout.write('' % (c['name'], c['nspf'], width, c['nspares'], c['ndata'], c['capacity'], c['adjusted'])) else: sys.stdout.write("%-11s%7s%7s%7d%13d%15.2f%15.2f\n" % (c['name'], c['nspf'], width, c['nspares'], c['ndata'], c['capacity'], c['adjusted'])) if htmlOutput: print "
TypeNSPFWidthSparesData DrivesRAW (TB)Usable (TiB)
%s%s%s%d%d%5.2f%5.2f
" print "

As of 2009.Q3, the raidz2 wide profile has been deprecated." print " New configurations should use the raidz3 wide profile instead

" else: print "\n** As of 2009.Q3, the raidz2 wide profile has been deprecated." print "** New configurations should use the raidz3 wide profile." sys.exit(0)