#!/usr/bin/python # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # # Sun Storage 7000 size calculator version 2009.Q2 # # 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' + \ 'or, specifying "3 t2 t1 t" will have a 7210 and 2 J4500s, the first with ' + \ 'two\nlogzilla devices, the second with one logzilla, and the last ' + \ 'without 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).' progname = sys.argv[0] del sys.argv[0] def usage(): print 'usage: ' + progname + \ ' ' print '\t[jbod layout] [add ...]\n' print help sys.exit(2) print 'Sun Storage 7000 Size Calculator Version 2009.Q2' 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 } 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 } stripe = { 'type': 'stripe', 'disktype': 'data', 'modelOnly': True } options = [ raidz2, raidz2_n, raidz2_wide, raidz2_n_wide, mirror, mirror_n, stripe, raidz1, raidz1_n ] jbod = { 'akch_disk': [] } for n in xrange(0, 24): jbod['akch_disk'].append({ 'akch_type': 'data', 'akch_size': 1, 'akch_device': 'none', 'akch_faulted': False, 'akch_present': True, }) configs = {} first = True while len(sys.argv) > 0: config = { 'akch_chassis': [] } ndrives = 0; njbods = int(sys.argv[0]) del sys.argv[0] #print 'njbods = %d'%(njbods) 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: #print 'jbod %d = ST7210 Ctlr'%(idx) 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 #else: #print'jbod %d = J4500'%(idx) for n in xrange(24, 48): config['akch_chassis'][idx]['akch_disk'] \ .append({ 'akch_type': 'data', 'akch_size': 1, 'akch_device': 'none', 'akch_faulted': False, 'akch_present': True, }) ndrives += 24 if m.group(3): for i in xrange(0, 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.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'] c['adjusted'] += adjusted c['valid'] = True first = False; if len(sys.argv) > 0: assert sys.argv[0] == 'add' del sys.argv[0] 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']) 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'])) sys.exit(0)