Mercurial > illumos > illumos-gate
view usr/src/cmd/beadm/BootEnvironment.py @ 13025:3c7681e3e323
PSARC 2010/059 SNAP BE Management
6964804 SNAP BE management into ON
6971379 libbe should capture and give useful error when installgrub or ict.py fails.
6971390 beadm does not support labeled brand zones
6971394 BEADM_ERR_BE_DOES_NOT_EXIST has an extra space
6971397 libbe error messages need internationalization
6971402 Remove be_get_last_zone_be_callback
6971409 be_create_menu returns errors from both be_errno_t and errno sets
author | Glenn Lagasse <glenn.lagasse@oracle.com> |
---|---|
date | Wed, 04 Aug 2010 12:28:19 -0700 |
parents | |
children |
line wrap: on
line source
# CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # """Boot Environment classes used by beadm.""" import datetime class BootEnvironment: """Boot Environment object that is used by beadm to manage command line options, arguments and the log.""" def __init__(self): self.trgt_rpool = None self.trgt_be_name_or_snapshot = None self.src_be_name_or_snapshot = None self.properties = {} self.log_id = None self.log = None self.msg_buf = {} self.description = None class listBootEnvironment: """Base class for beadm list Determine the BE's to display. Prints command output according to option: -d - dataset -s - snapshot -a - all (both dataset and snapshot) <none> - only BE information The -H option produces condensed, parseable output The ';' delimits each field in the output. BEs with multiple datasets will have multiple lines in the output. """ def list(self, be_list, ddh, be_name): """ print all output for beadm list command be_list - list of all BEs ddh - if True, Do not Display Headers - just parseable data be_name - user-specified BE, if any returns 0 for success side effect: beadm list output printed to stdout """ #If we're listing Headers, initialize the array holding the #column widths with the header widths themselves. Later on, #the data in this array will get adjusted as we process actual #row data and find that a piece of data is wider than its #column header. bemaxout = [0 for i in range(len(self.hdr[0]))] if not ddh: #iterate all header rows since their fields may not #be of equal length. for header in self.hdr: icol = 0 for hc in header: if len(hc) + 1 > bemaxout[icol]: bemaxout[icol] = len(hc) + 1 icol += 1 #collect BEs beout = {} #matrix of output text [row][attribute] beoutname = {} #list of BE names [row] be_space = {} #space used totals for BE [BE name]['space_used','ibei'] ibe = 0 #BE index spacecol = -1 #to contain column where space used is displayed for be in be_list: if 'orig_be_name' in be: cur_be = be['orig_be_name'] cur_be_obj = be #if BE name specified, collect matching BEs if be_name is not None and not self.beMatch(be, be_name): continue attrs = () #identify BE|dataset|snapshot attributes att = '' for att in ('orig_be_name', 'dataset', 'snap_name'): if att in be and att in self.lattrs: attrs = self.lattrs[att] if att == 'orig_be_name': be_space[cur_be] = {} be_space[cur_be]['space_used'] = 0 be_space[cur_be]['ibe'] = ibe if not ddh and len(cur_be) + 1 > bemaxout[0]: bemaxout[0] = len(cur_be) + 1 break beout[ibe] = {} beoutname[ibe] = cur_be icol = 0 #first column for at in attrs: #for option -s, withhold subordinate datasets if self.__class__.__name__ == 'SnapshotList' and \ att == 'snap_name' and 'snap_name' in be and \ '/' in be[att]: break #convert output to readable format and save save = self.getAttr(at, be, ddh, cur_be_obj) beout[ibe][at] = save #maintain maximum column widths if not ddh and len(save) + 1 > bemaxout[icol]: bemaxout[icol] = len(save) + 1 #sum all snapshots for BE if at == 'space_used' and 'space_used' in be: spacecol = icol icol += 1 #next column ibe += 1 if 'space_used' in be: #sum all snapshots and datasets for BE in 'beadm list' if isinstance(self, BEList): be_space[cur_be]['space_used'] += be.get('space_used') elif cur_be in be_space and \ ('space_used' not in be_space[cur_be] or be_space[cur_be]['space_used'] == 0): #list space used separately for other options be_space[cur_be]['space_used'] = be.get('space_used') #output format total lengths for each BE with any snapshots for cur_be in be_space: save = self.getSpaceValue(be_space[cur_be]['space_used'], ddh) ibe = be_space[cur_be]['ibe'] beout[ibe]['space_used'] = save #expand column if widest column entry if (spacecol != -1) and \ (not ddh and len(save) + 1 > bemaxout[spacecol]): bemaxout[spacecol] = len(save) + 1 #print headers in columns if not ddh: for header in self.hdr: outstr = '' for icol in range(len(header)): outstr += header[icol].ljust(bemaxout[icol]) if outstr != '': print outstr #print collected output in columns outstr = '' prev_be = None cur_be = None for ibe in beout: #index output matrix if beoutname[ibe] != None: cur_be = beoutname[ibe] #find attributes for BE type curtype = None for att in ('orig_be_name', 'dataset', 'snap_name'): if att in beout[ibe]: attrs = self.lattrs[att] curtype = att break if curtype == None: #default to BE curtype = 'orig_be_name' if 'orig_be_name' in self.lattrs: attrs = self.lattrs['orig_be_name'] else: attrs = () if not ddh: if prev_be != cur_be and cur_be != None: #for -d,-s,-a, print BE alone on line if self.__class__.__name__ != 'BEList': print cur_be prev_be = cur_be #print for one BE/snapshot/dataset icol = 0 #first column #if this is a 'dataset' or 'snap_name', start line with BE #name token if ddh and curtype != 'orig_be_name': outstr = cur_be for at in attrs: #for each attribute specified in table if ddh: #add separators for parsing if outstr != '': outstr += ';' #attribute separator if at in beout[ibe] and beout[ibe][at] != '-' and \ beout[ibe][at] != '': outstr += beout[ibe][at] else: #append text justified in column if at in beout[ibe]: outstr += beout[ibe][at].ljust(bemaxout[icol]) icol += 1 #next column if outstr != '': print outstr outstr = '' return 0 def beMatch(self, be, be_name): """find match on user-specified BE.""" if 'orig_be_name' in be: return be.get('orig_be_name') == be_name if 'dataset' in be: if be.get('dataset') == be_name: return True out = be.get('dataset').split("/") return out[0] == be_name if 'snap_name' in be: if be.get('snap_name') == be_name: return True out = be.get('snap_name').split('@') if out[0] == be_name: return True out = be.get('snap_name').split('/') return out[0] == be_name return False def getAttr(self, at, be, ddh, beobj): """ Extract information by attribute and format for printing returns '?' if normally present attribute not found - error. """ if at == 'blank': return ' ' if at == 'dash': return '-' if at == 'orig_be_name': if at not in be: return '-' ret = be[at] if ddh or self.__class__.__name__ == 'BEList': return ret return ' ' + ret #indent if at == 'snap_name': if at not in be: return '-' if self.__class__.__name__ == 'CompleteList': ret = self.prependRootDS(be[at], beobj) else: ret = be[at] if ddh: return ret return ' ' + ret #indent if at == 'dataset': if at not in be: return '-' if self.__class__.__name__ == 'DatasetList' or \ self.__class__.__name__ == 'CompleteList': ret = self.prependRootDS(be[at], beobj) else: ret = be[at] if ddh: return ret return ' ' + ret #indent if at == 'active': if at not in be: return '-' ret = '' if 'active' in be and be['active']: ret += 'N' if 'active_boot' in be and be['active_boot']: ret += 'R' if ret == '': return '-' return ret if at == 'mountpoint': if at not in be: return '-' if 'mounted' not in be or not be['mounted']: return '-' return be[at] if at == 'space_used': if at not in be: return '0' return self.getSpaceValue(be[at], ddh) if at == 'mounted': if at not in be: return '-' return be[at] if at == 'date': if at not in be: return '?' if ddh: return str(be[at]) #timestamp in seconds sec = str(datetime.datetime.fromtimestamp(be[at])) return sec[0:len(sec)-3] #trim seconds if at == 'policy': if at not in be: return '?' return be[at] if at == 'root_ds': if at not in be: return '?' if ddh or self.__class__.__name__ == 'BEList': return be[at] return ' ' + be[at] if at == 'uuid_str': if at not in be: return '-' return be[at] #default case - no match on attribute return be[at] def getSpaceValue(self, num, ddh): """Readable formatting for disk space size.""" if ddh: return str(num) #return size in bytes as string kilo = 1024.0 mega = 1048576.0 giga = 1073741824.0 tera = 1099511627776.0 if num == None: return '0' if num < kilo: return str(num) + 'B' if num < mega: return str('%.1f' % (num / kilo)) + 'K' if num < giga: return str('%.2f' % (num / mega)) + 'M' if num < tera: return str('%.2f' % (num / giga)) + 'G' return str('%.2f' % (num / tera)) + 'T' def prependRootDS(self, val, beobj): """Prepend root dataset name with BE name stripped.""" root_ds = beobj.get('root_ds') return root_ds[0:root_ds.rfind('/')+1] + val """Top level "beadm list" derived classes defined here. Only table definition is done here - all methods are in the base class. Tables driving list: hdr - list of text to output for each column lattrs - dictionary of attributes Each entry specifies either BE, dataset, snapshot with an attribute key: orig_be_name - for BEs dataset - for datasets snap_name - for snapshots Each list item in entry indicates specific datum for column Number of hdr columns must equal number of lattrs entries unless ddh (dontDisplayHeaders) is true. """ class BEList(listBootEnvironment): """specify header and attribute information for BE-only output""" def __init__(self, ddh): """Init function for the class.""" self.hdr = \ ('BE','Active','Mountpoint','Space','Policy','Created'), \ ('--','------','----------','-----','------','-------') if ddh: self.lattrs = {'orig_be_name':('orig_be_name', 'uuid_str', 'active', 'mountpoint', 'space_used', 'policy', 'date')} else: self.lattrs = {'orig_be_name':('orig_be_name', 'active', 'mountpoint', 'space_used', 'policy', 'date')} class DatasetList(listBootEnvironment): """ specify header and attribute information for dataset output, -d option """ def __init__(self, ddh): """Init function for the class.""" self.hdr = \ ('BE/Dataset','Active','Mountpoint','Space','Policy','Created'), \ ('----------','------','----------','-----','------','-------') if ddh: self.lattrs = { \ 'orig_be_name':('orig_be_name', 'root_ds', 'active', 'mountpoint', 'space_used', 'policy', 'date'), \ 'dataset':('dataset', 'dash', 'mountpoint', 'space_used', 'policy', 'date')} else: self.lattrs = { \ 'orig_be_name':('root_ds', 'active', 'mountpoint', 'space_used', 'policy', 'date'), \ 'dataset':('dataset', 'dash', 'mountpoint', 'space_used', 'policy', 'date')} class SnapshotList(listBootEnvironment): """ specify header and attribute information for snapshot output, -s option """ def __init__(self, ddh): """Init function for the class.""" self.hdr = \ ('BE/Snapshot','Space','Policy','Created'), \ ('-----------','-----','------','-------') self.lattrs = {'snap_name':('snap_name', 'space_used', 'policy', 'date')} class CompleteList(listBootEnvironment): """ specify header and attribute information for BE and/or dataset and/or snapshot output, -a or -ds options """ def __init__(self, ddh): """Init function for the class.""" self.hdr = \ ('BE/Dataset/Snapshot','Active','Mountpoint','Space','Policy','Created'), \ ('-------------------','------','----------','-----','------','-------') if ddh: self.lattrs = { \ 'orig_be_name':('orig_be_name', 'root_ds', 'active', 'mountpoint', 'space_used', 'policy', 'date'), 'dataset':('dataset', 'dash', 'mountpoint', 'space_used', 'policy', 'date'), 'snap_name':('snap_name', 'dash', 'dash', 'space_used', 'policy', 'date')} else: self.lattrs = { \ 'orig_be_name':('root_ds', 'active', 'mountpoint', 'space_used', 'policy', 'date'), \ 'dataset':('dataset', 'dash', 'mountpoint', 'space_used', 'policy', 'date'), 'snap_name':('snap_name', 'dash', 'dash', 'space_used', 'policy', 'date')}