Example #1
0
    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')]
Example #2
0
    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)
Example #3
0
    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
Example #4
0
    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'
Example #5
0
    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
Example #6
0
    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'
Example #7
0
    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)
Example #8
0
    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')
        ]
Example #9
0
    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'
Example #10
0
    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')
        ]
Example #11
0
    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
Example #12
0
    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
Example #13
0
    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)
Example #14
0
    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)
Example #15
0
    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)
Example #16
0
    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'
Example #17
0
    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') ]
Example #18
0
    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)