def configure_from_node(self, node, defaults, parent): DynamicNamedXMLConfigurable.configure_from_node(self, node, defaults, parent) # Add drhost bits, if available. # This is done here, rather than as a separate object, # to avoid a separate class that may not really be necessary self.children['drhostname'] = [x.attrib['name'] for x in node.findall('drhost')]
def _configure_mandatory_attributes(self, node, defaults): # if getattr(self, 'name', None) is None: # raise KeyError("Host does not have 'name' set") # if getattr(self, 'operatingsystem', None) is None: # raise KeyError("Host '%s' does not have 'operatingsystem' set" % self.name) DynamicNamedXMLConfigurable.configure_mandatory_attributes(self, node, defaults)
def configure_optional_attributes(self, node, defaults): DynamicNamedXMLConfigurable.configure_optional_attributes( self, node, defaults) # If targetvolume isn't defined, targetaggregate is required. if self.targetvolume is None and self.targetaggregate is None: raise KeyError("'%s' node attribute 'targetaggregate' is not set" % self.xmltag) # Use a default multiplier if one isn't specified if self.multiplier is None: try: self.multiplier = defaults.getfloat(self.defaults_section, 'multiplier') except (NoSectionError, NoOptionError): self.multiplier = 2.5 pass else: self.multiplier = float(self.multiplier) # Convert targetusable from text to a float if self.targetusable is not None: self.targetusable = float(self.targetusable) pass if self.targetsuffix is None: try: self.targetsuffix = defaults.get(self.defaults_section, 'volsuffix') except (NoSectionError, NoOptionError): self.targetsuffix = 'b' pass pass
def configure_optional_attributes(self, node, defaults): DynamicNamedXMLConfigurable.configure_optional_attributes( self, node, defaults) # Aggregate type defaults to 'data' if self.type is None: self.type = 'data'
def configure_optional_attributes(self, node, defaults): DynamicNamedXMLConfigurable.configure_optional_attributes(self, node, defaults) # If targetvolume isn't defined, targetaggregate is required. if self.targetvolume is None and self.targetaggregate is None: raise KeyError("'%s' node attribute 'targetaggregate' is not set" % self.xmltag) # Use a default multiplier if one isn't specified if self.multiplier is None: try: self.multiplier = defaults.getfloat(self.defaults_section, "multiplier") except (NoSectionError, NoOptionError): self.multiplier = 2.5 pass else: self.multiplier = float(self.multiplier) # Convert targetusable from text to a float if self.targetusable is not None: self.targetusable = float(self.targetusable) pass if self.targetsuffix is None: try: self.targetsuffix = defaults.get(self.defaults_section, "volsuffix") except (NoSectionError, NoOptionError): self.targetsuffix = "b" pass pass
def configure_optional_attributes(self, node, defaults): DynamicNamedXMLConfigurable.configure_optional_attributes(self, node, defaults) if getattr(self, 'security', None) is None: try: self.security = defaults.get('qtree', 'default_security') except (NoSectionError, NoOptionError): self.security = 'unix'
def _configure_mandatory_attributes(self, node, defaults): # if getattr(self, 'name', None) is None: # raise KeyError("Host does not have 'name' set") # if getattr(self, 'operatingsystem', None) is None: # raise KeyError("Host '%s' does not have 'operatingsystem' set" % self.name) DynamicNamedXMLConfigurable.configure_mandatory_attributes( self, node, defaults)
def configure_from_node(self, node, defaults, parent): DynamicNamedXMLConfigurable.configure_from_node( self, node, defaults, parent) self.volume = parent self.qtreenode = node self.children['exportalias'] = [ x.text for x in node.findall('exportalias') ]
def configure_optional_attributes(self, node, defaults): DynamicNamedXMLConfigurable.configure_optional_attributes( self, node, defaults) if getattr(self, 'security', None) is None: try: self.security = defaults.get('qtree', 'default_security') except (NoSectionError, NoOptionError): self.security = 'unix'
def configure_from_node(self, node, defaults, parent): DynamicNamedXMLConfigurable.configure_from_node( self, node, defaults, parent) # Add drhost bits, if available. # This is done here, rather than as a separate object, # to avoid a separate class that may not really be necessary self.children['drhostname'] = [ x.attrib['name'] for x in node.findall('drhost') ]
def configure_optional_attributes(self, node, defaults): DynamicNamedXMLConfigurable.configure_optional_attributes(self, node, defaults) # If the location for the host is set, use that, else # default to the same location as the containing site if self.location is None: location = self.parent.location # Is the host virtual or physical? if self.is_virtual is None: self.is_virtual = False elif self.is_virtual.lower() == 'yes': self.is_virtual = True log.debug("Host '%s' is virtual.", hostname) else: self.is_virtual = False
def configure_optional_attributes(self, node, defaults): DynamicNamedXMLConfigurable.configure_optional_attributes( self, node, defaults) # If the location for the host is set, use that, else # default to the same location as the containing site if self.location is None: location = self.parent.location # Is the host virtual or physical? if self.is_virtual is None: self.is_virtual = False elif self.is_virtual.lower() == 'yes': self.is_virtual = True log.debug("Host '%s' is virtual.", hostname) else: self.is_virtual = False
def configure_from_node(self, node, defaults, parent): """ Volume configuration is quite complex, due to the way we attempt to cater for all kinds of situations automatically, using configurable defaults and various overrides. """ self.parent = parent DynamicNamedXMLConfigurable.configure_from_node(self, node, defaults, parent) # Check if iscsi is an enabled protocol. If so, use 'iscsi_snapspace' instead # of snapreserve #if 'iscsi' in [ x.name for x in self.get_protocols() ]: if 'iscsi' == self.protocol: self.snapreserve = 0 if getattr(self, 'iscsi_snapspace', None): self.iscsi_snapspace = defaults.getint('volume', 'default_iscsi_snapspace') else: self.iscsi_snapspace = int(self.iscsi_snapspace) pass pass # iSCSI LUN sizing is... interesting # Best practice is to have no snapreserve for volumes # used for iscsi, but we need to have some storage # available for snapshots. Because LUNs are just files full # of blocks, we have to allocate enough storage for all # of the blocks to change, so we need 2 * LUNsize GiB to # store the snapshots. # If you're not using snapshots, you will need a little extra # space in the volume so the LUN can fit within it. The LUN # can't take up 100% of the volume (i.e.: A LUN of 100GiB # will require a volume of 101GiB in size) log.debug("volume proto is iscsi") # If snapshots are configured, double the usable storage to allow for 50% 'snapreserve' if len(self.get_snaprefs()) > 0 or \ len(self.get_snapvaultrefs()) > 0 or \ len(self.get_snapmirrorrefs()) > 0 or \ len(self.get_snapvaultmirrorrefs()) > 0: log.debug("snapshots present. doubling usable space of %s GiB for iscsi volume", self.usable) #snapdiv = (100 - float(iscsi_snapspace))/100 snapspace = self.usable * ( float(iscsi_snapspace)/100 ) log.debug("Adding iscsi_snapspace (%s%%) of %s GiB", iscsi_snapspace, snapspace) self.usable = (self.usable * 2.0) + snapspace log.debug("usable is now: %s GiB, iscsi_usable is: %s GiB", self.usable, self.iscsi_usable) else: # If no snapshots are configured, make the raw slightly more than usable log.debug("No snapshots, adding 1 GiB usable to volume size.") self.raw = self.usable + 1 pass pass # self.snapref = snapref # self.snapvaultref = snapvaultref # self.snapmirrorref = snapmirrorref # self.snapvaultmirrorref = snapvaultmirrorref # Lists of the actual snapX objects, added when they're created self.snaps = [] self.snapvaults = [] self.snapmirrors = [] #self.qtrees = {} # Set volume options as a dictionary options = {} if len(self.children['option']) == 0: # FIXME: deal with user errors in the config file better for opt in defaults.get('volume', 'default_options').split(','): name, value = opt.split('=') options[name] = value pass else: for opt in self.children['option']: name, value = opt.split('=') options[name] = value pass pass self.children['option'] = options self.volnode = node # If volume export is not allowed, check that qtrees exist in the # volume. If not, create a single default data qtree. self.check_volume_export_allowed(defaults) self.autosize = None self.autodelete = None log.debug("volume usable is: %f", self.usable)
def configure_optional_attributes(self, node, defaults): DynamicNamedXMLConfigurable.configure_optional_attributes(self, node, defaults) # Set volume name prefix self.prefix = getattr(self, 'prefix', '') # Set volume name suffix self.suffix = getattr(self, 'suffix', '') # Set volume name suffix if self.type is None: self.type = defaults.get('volume', 'default_vol_type') # Check to see if we want to restart the volume numbering # FIXME: Get the current volume numbering thing from parent volnum = getattr(self, 'restartnumbering', None) if volnum is None: # Don't grab a new number if this is the root volume # for a vfiler. Only number data volumes. if self.type != 'root': self.volnum = self.parent.get_next_volnum() else: self.volnum = int(volnum) parent.set_volnum(self.volnum) # Set usable storage if getattr(self, 'usable', None) is None: self.usable = defaults.getfloat('volume', 'default_size') else: self.usable = float(self.usable) # Set allowable protocols for the volume # The volume protocol is either a protocol set in the volume definition # using the 'proto' attribute, or it will be the first protocol in # the list of possible protocols for the vfiler. # If neither of these are set, it will be set to the default try: self.protocol = node.attrib['protocol'].lower() log.debug("Proto defined for volume: %s", self.protocol) except KeyError: try: self.protocol = node.xpath("ancestor::*/vfiler/protocol/text()")[0].lower() #log.debug("Found proto in vfiler ancestor: %s", self.protocol) except IndexError: self.protocol = defaults.get('protocol', 'default_storage_protocol') log.debug("Proto set to default: %s", self.protocol) # Set snapreserve and iSCSI snapspace if getattr(self, 'snapreserve', None) is None: # If the volume is a type that we know has a high rate of change, # we set a different snapreserve. try: highdelta_types = defaults.get('volume', 'high_delta_types') except (NoSectionError, NoOptionError): highdelta_types = [] pass if self.type in highdelta_types: self.snapreserve = defaults.getint('volume', 'default_highdelta_snapreserve') else: self.snapreserve = defaults.getint('volume', 'default_snapreserve') else: self.snapreserve = float(self.snapreserve) pass # Round the snapreserve self.snapreserve = int(round(self.snapreserve)) # A special kind of usable that is used for the actual iscsi LUN space # iSCSI really is a pain to allocate on WAFL self.iscsi_usable = self.usable try: self.iscsi_snapspace = defaults.get('volume', 'iscsi_snapspace') except (NoOptionError, NoSectionError): self.iscsi_snapspace = 0 if getattr(self, 'raw', None) is None: try: self.raw = self.usable / ( (100 - float(self.snapreserve) )/100 ) except ZeroDivisionError, e: log.critical("snapreserve of 100% is not a valid value. You probably mean 50%.") raise ZeroDivisionError(e)
def configure_from_node(self, node, defaults, parent): """ Volume configuration is quite complex, due to the way we attempt to cater for all kinds of situations automatically, using configurable defaults and various overrides. """ self.parent = parent DynamicNamedXMLConfigurable.configure_from_node( self, node, defaults, parent) # Check if iscsi is an enabled protocol. If so, use 'iscsi_snapspace' instead # of snapreserve #if 'iscsi' in [ x.name for x in self.get_protocols() ]: if 'iscsi' == self.protocol: self.snapreserve = 0 if getattr(self, 'iscsi_snapspace', None): self.iscsi_snapspace = defaults.getint( 'volume', 'default_iscsi_snapspace') else: self.iscsi_snapspace = int(self.iscsi_snapspace) pass pass # iSCSI LUN sizing is... interesting # Best practice is to have no snapreserve for volumes # used for iscsi, but we need to have some storage # available for snapshots. Because LUNs are just files full # of blocks, we have to allocate enough storage for all # of the blocks to change, so we need 2 * LUNsize GiB to # store the snapshots. # If you're not using snapshots, you will need a little extra # space in the volume so the LUN can fit within it. The LUN # can't take up 100% of the volume (i.e.: A LUN of 100GiB # will require a volume of 101GiB in size) log.debug("volume proto is iscsi") # If snapshots are configured, double the usable storage to allow for 50% 'snapreserve' if len(self.get_snaprefs()) > 0 or \ len(self.get_snapvaultrefs()) > 0 or \ len(self.get_snapmirrorrefs()) > 0 or \ len(self.get_snapvaultmirrorrefs()) > 0: log.debug( "snapshots present. doubling usable space of %s GiB for iscsi volume", self.usable) #snapdiv = (100 - float(iscsi_snapspace))/100 snapspace = self.usable * (float(iscsi_snapspace) / 100) log.debug("Adding iscsi_snapspace (%s%%) of %s GiB", iscsi_snapspace, snapspace) self.usable = (self.usable * 2.0) + snapspace log.debug("usable is now: %s GiB, iscsi_usable is: %s GiB", self.usable, self.iscsi_usable) else: # If no snapshots are configured, make the raw slightly more than usable log.debug("No snapshots, adding 1 GiB usable to volume size.") self.raw = self.usable + 1 pass pass # self.snapref = snapref # self.snapvaultref = snapvaultref # self.snapmirrorref = snapmirrorref # self.snapvaultmirrorref = snapvaultmirrorref # Lists of the actual snapX objects, added when they're created self.snaps = [] self.snapvaults = [] self.snapmirrors = [] #self.qtrees = {} # Set volume options as a dictionary options = {} if len(self.children['option']) == 0: # FIXME: deal with user errors in the config file better for opt in defaults.get('volume', 'default_options').split(','): name, value = opt.split('=') options[name] = value pass else: for opt in self.children['option']: name, value = opt.split('=') options[name] = value pass pass self.children['option'] = options self.volnode = node # If volume export is not allowed, check that qtrees exist in the # volume. If not, create a single default data qtree. self.check_volume_export_allowed(defaults) self.autosize = None self.autodelete = None log.debug("volume usable is: %f", self.usable)
def configure_optional_attributes(self, node, defaults): DynamicNamedXMLConfigurable.configure_optional_attributes(self, node, defaults) # Aggregate type defaults to 'data' if self.type is None: self.type = 'data'
def configure_from_node(self, node, defaults, parent): DynamicNamedXMLConfigurable.configure_from_node(self, node, defaults, parent) self.volume = parent self.qtreenode = node self.children['exportalias'] = [ x.text for x in node.findall('exportalias') ]
def configure_optional_attributes(self, node, defaults): DynamicNamedXMLConfigurable.configure_optional_attributes( self, node, defaults) # Set volume name prefix self.prefix = getattr(self, 'prefix', '') # Set volume name suffix self.suffix = getattr(self, 'suffix', '') # Set volume name suffix if self.type is None: self.type = defaults.get('volume', 'default_vol_type') # Check to see if we want to restart the volume numbering # FIXME: Get the current volume numbering thing from parent volnum = getattr(self, 'restartnumbering', None) if volnum is None: # Don't grab a new number if this is the root volume # for a vfiler. Only number data volumes. if self.type != 'root': self.volnum = self.parent.get_next_volnum() else: self.volnum = int(volnum) parent.set_volnum(self.volnum) # Set usable storage if getattr(self, 'usable', None) is None: self.usable = defaults.getfloat('volume', 'default_size') else: self.usable = float(self.usable) # Set allowable protocols for the volume # The volume protocol is either a protocol set in the volume definition # using the 'proto' attribute, or it will be the first protocol in # the list of possible protocols for the vfiler. # If neither of these are set, it will be set to the default try: self.protocol = node.attrib['protocol'].lower() log.debug("Proto defined for volume: %s", self.protocol) except KeyError: try: self.protocol = node.xpath( "ancestor::*/vfiler/protocol/text()")[0].lower() #log.debug("Found proto in vfiler ancestor: %s", self.protocol) except IndexError: self.protocol = defaults.get('protocol', 'default_storage_protocol') log.debug("Proto set to default: %s", self.protocol) # Set snapreserve and iSCSI snapspace if getattr(self, 'snapreserve', None) is None: # If the volume is a type that we know has a high rate of change, # we set a different snapreserve. try: highdelta_types = defaults.get('volume', 'high_delta_types') except (NoSectionError, NoOptionError): highdelta_types = [] pass if self.type in highdelta_types: self.snapreserve = defaults.getint( 'volume', 'default_highdelta_snapreserve') else: self.snapreserve = defaults.getint('volume', 'default_snapreserve') else: self.snapreserve = float(self.snapreserve) pass # Round the snapreserve self.snapreserve = int(round(self.snapreserve)) # A special kind of usable that is used for the actual iscsi LUN space # iSCSI really is a pain to allocate on WAFL self.iscsi_usable = self.usable try: self.iscsi_snapspace = defaults.get('volume', 'iscsi_snapspace') except (NoOptionError, NoSectionError): self.iscsi_snapspace = 0 if getattr(self, 'raw', None) is None: try: self.raw = self.usable / ( (100 - float(self.snapreserve)) / 100) except ZeroDivisionError, e: log.critical( "snapreserve of 100% is not a valid value. You probably mean 50%." ) raise ZeroDivisionError(e)