示例#1
0
    def write(self, header = True):

        res = ""

        if header:
            res += SAVE_HEADER

        keys = list(set(( x for x in self.formulae.keys()
                          if x.startswith("eth") )))
        keys.sort(key=lambda x: int(x[3:]))

        for target in keys:
            method, value = self.formulae[target]

            if method not in StaticRules.methods:
                LOG.warning("Method %s not recognised.  Ignoring" % (method,))
                continue

            # If we have a validator, test the valididy
            if method in StaticRules.validators:
                if StaticRules.validators[method].match(value) is None:
                    LOG.warning("Invalid %s value '%s'. Ignoring"
                                % (method, value))
                    continue

            res += "%s:%s=\"%s\"\n" % (target, method, value)

        return res
示例#2
0
    def save(self, header = True):

        fd = None

        try:
            try:
                # If we were given a path, try opening and writing to it
                if self.path:
                    fd = open(self.path, "w")
                    fd.write(self.write(header))

                # else if we were given a file descriptor, just read it
                elif self.fd:
                    self.fd.write(self.write(header))

                # else there is nothing we can do
                else:
                    LOG.error("No source of data to parse")
                    return False

            except IOError, e:
                LOG.error("IOError while reading file: %s" % (e,))
                return False
        finally:
            # Ensure we alway close the file descriptor we opened
            if fd:
                fd.close()

        return True
示例#3
0
    def save(self, header=True):

        fd = None

        try:
            try:
                # If we were given a path, try opening and writing to it
                if self.path:
                    fd = open(self.path, "w")
                    fd.write(self.write(header))

                # else if we were given a file descriptor, just read it
                elif self.fd:
                    self.fd.write(self.write(header))

                # else there is nothing we can do
                else:
                    LOG.error("No source of data to parse")
                    return False

            except IOError, e:
                LOG.error("IOError while reading file: %s" % (e, ))
                return False
        finally:
            # Ensure we alway close the file descriptor we opened
            if fd:
                fd.close()

        return True
示例#4
0
    def write(self, header=True):

        res = ""

        if header:
            res += SAVE_HEADER

        keys = list(
            set((x for x in self.formulae.keys() if x.startswith("eth"))))
        keys.sort(key=lambda x: int(x[3:]))

        for target in keys:
            method, value = self.formulae[target]

            if method not in StaticRules.methods:
                LOG.warning("Method %s not recognised.  Ignoring" % (method, ))
                continue

            # If we have a validator, test the valididy
            if method in StaticRules.validators:
                if StaticRules.validators[method].match(value) is None:
                    LOG.warning("Invalid %s value '%s'. Ignoring" %
                                (method, value))
                    continue

            res += "%s:%s=\"%s\"\n" % (target, method, value)

        return res
示例#5
0
    def save(self, header = True):
        """
        Save the dynamic rules to a file/path.
        Returns boolean indicating success or failure.
        """

        fd = None

        try:
            try:
                # If we were given a path, try opening and writing to it
                if self.path:
                    fd = open(self.path, "w")
                    fd.write(self.write(header))

                # else if we were given a file descriptor, just write to it
                elif self.fd:
                    self.fd.write(self.write(header))

                # else there is nothing we can do
                else:
                    LOG.error("No source of data to parse")
                    return False

            except IOError, e:
                LOG.error("IOError while reading file: %s" % (e,))
                return False
        finally:
            # Ensure we alway close the file descriptor we opened
            if fd:
                fd.close()

        return True
示例#6
0
 def validate(entry):
     try:
         MACPCI(entry[0], entry[1], tname=entry[2])
         return True
     except Exception, e:
         LOG.warning("Failed to validate '%s' because '%s'"
                     % (entry, e))
         return False
示例#7
0
 def validate(entry):
     try:
         # iBFT NICs are ignored so don't have a tname
         if entry[2] is None:
             return False
         MACPCI(entry[0], entry[1], tname=entry[2])
         return True
     except Exception, e:
         LOG.warning("Failed to validate '%s' because '%s'"
                     % (entry, e))
         return False
示例#8
0
def __rename_nic(nic, name, transactions, cur_state):
    """
    Rename a specified nic to name.
    It checkes in possibly_aliased for nics which currently have name, and
    renames them sideways.
    The caller should ensure that no nics in cur_state have already been renamed
    to name, and that name is a valid nic name
    """

    # Assert that name is valid
    assert VALID_ETH_NAME.match(name) is not None
    # Assert that name is not already taken in the current state
    assert name not in map(lambda x: x.tname, cur_state)

    # Given the previous assert, only un-renamed nics in the current state can
    # possibly alias the new name
    aliased = util.get_nic_with_kname(
        filter(lambda x: x.tname is None, cur_state), name)

    if aliased is None:
        # Using this rule will not alias another currently present NIC
        LOG.debug("Renaming unaliased nic '%s' to '%s'" % (nic, name))
        nic.tname = name
        transactions.append((nic.kname, name))

    elif aliased == nic and aliased.kname == nic.kname:
        # The nic is already named correctly.  Just update tname
        LOG.debug("Nic '%s' is already named correctly" % (nic,))
        nic.tname = nic.kname

    else:
        # Another nic is in the way for applying the rule.  Move it sideways

        # TODO: given new assertions, will this ever be nessesary?
        if aliased.kname[:5] == "side-":
            aliased_eth = aliased.kname.split('-')[2]
        else:
            aliased_eth = aliased.kname

        tempname = util.get_new_temp_name(cur_state, aliased_eth)
        LOG.debug("Nic '%s' aliases rename of '%s' to '%s'"
                  % (aliased, nic, name))

        # Rename aliased nic sideways
        LOG.debug("Renaming aliased nic to '%s'" % (tempname,))
        transactions.append((aliased.kname, tempname))
        aliased.kname = tempname

        # And then rename the original nic
        LOG.debug("Renaming original nic to '%s'" % (name,))
        nic.tname = name
        transactions.append((nic.kname, name))
示例#9
0
def __rename_nic(nic, name, transactions, cur_state):
    """
    Rename a specified nic to name.
    It checkes in possibly_aliased for nics which currently have name, and
    renames them sideways.
    The caller should ensure that no nics in cur_state have already been renamed
    to name, and that name is a valid nic name
    """

    # Assert that name is valid
    assert VALID_ETH_NAME.match(name) is not None
    # Assert that name is not already taken in the current state
    assert name not in map(lambda x: x.tname, cur_state)

    # Given the previous assert, only un-renamed nics in the current state can
    # possibly alias the new name
    aliased = util.get_nic_with_kname(
        filter(lambda x: x.tname is None, cur_state), name)

    if aliased is None:
        # Using this rule will not alias another currently present NIC
        LOG.debug("Renaming unaliased nic '%s' to '%s'" % (nic, name))
        nic.tname = name
        transactions.append((nic.kname, name))

    elif aliased == nic and aliased.kname == nic.kname:
        # The nic is already named correctly.  Just update tname
        LOG.debug("Nic '%s' is already named correctly" % (nic, ))
        nic.tname = nic.kname

    else:
        # Another nic is in the way for applying the rule.  Move it sideways

        # TODO: given new assertions, will this ever be nessesary?
        if aliased.kname[:5] == "side-":
            aliased_eth = aliased.kname.split('-')[2]
        else:
            aliased_eth = aliased.kname

        tempname = util.get_new_temp_name(cur_state, aliased_eth)
        LOG.debug("Nic '%s' aliases rename of '%s' to '%s'" %
                  (aliased, nic, name))

        # Rename aliased nic sideways
        LOG.debug("Renaming aliased nic to '%s'" % (tempname, ))
        transactions.append((aliased.kname, tempname))
        aliased.kname = tempname

        # And then rename the original nic
        LOG.debug("Renaming original nic to '%s'" % (name, ))
        nic.tname = name
        transactions.append((nic.kname, name))
示例#10
0
    def generate(self, state):
        """
        Make rules from the formulae based on global state.
        """

        # CA-75599 - check that state has no shared ppns.
        #  See net.biodevname.has_ppn_quirks() for full reason
        ppns = [ x.ppn for x in state if x.ppn is not None ]
        ppn_quirks = ( len(ppns) != len(set(ppns)) )

        if ppn_quirks:
            LOG.warning("Discovered physical policy naming quirks in provided "
                        "state.  Disabling 'method=ppn' generation")

        for target, (method, value) in self.formulae.iteritems():

            if method == "mac":

                for nic in state:
                    if nic.mac == value:
                        try:
                            rule = MACPCI(nic.mac, nic.pci, tname=target)
                        except Exception, e:
                            LOG.warning("Error creating rule: %s" % (e,))
                            continue
                        self.rules.append(rule)
                        break
                else:
                    LOG.warning("No NIC found with a MAC address of '%s' for "
                                "the %s static rule" % (value, target))
                continue

            elif method == "ppn":

                if ppn_quirks:
                    LOG.info("Not considering formula for '%s' due to ppn "
                             "quirks" % (target,))
                    continue

                for nic in state:
                    if nic.ppn == value:
                        try:
                            rule = MACPCI(nic.mac, nic.pci, tname=target)
                        except Exception, e:
                            LOG.warning("Error creating rule: %s" % (e,))
                            continue
                        self.rules.append(rule)
                        break
示例#11
0
    def generate(self, state):
        """
        Make rules from the formulae based on global state.
        """

        # CA-75599 - check that state has no shared ppns.
        #  See net.biodevname.has_ppn_quirks() for full reason
        ppns = [ x.ppn for x in state if x.ppn is not None ]
        ppn_quirks = ( len(ppns) != len(set(ppns)) )

        if ppn_quirks:
            LOG.warning("Discovered physical policy naming quirks in provided "
                        "state.  Disabling 'method=ppn' generation")

        for target, (method, value) in self.formulae.iteritems():

            if method == "mac":

                for nic in state:
                    if nic.mac == value:
                        try:
                            rule = MACPCI(nic.mac, nic.pci, tname=target)
                        except Exception, e:
                            LOG.warning("Error creating rule: %s" % (e,))
                            continue
                        self.rules.append(rule)
                        break
                else:
                    LOG.warning("No NIC found with a MAC address of '%s' for "
                                "the %s dynamic rule" % (value, target))
                continue

            elif method == "ppn":

                if ppn_quirks:
                    LOG.info("Not considering formula for '%s' due to ppn "
                             "quirks" % (target,))
                    continue

                for nic in state:
                    if nic.ppn == value:
                        try:
                            rule = MACPCI(nic.mac, nic.pci, tname=target)
                        except Exception, e:
                            LOG.warning("Error creating rule: %s" % (e,))
                            continue
                        self.rules.append(rule)
                        break
示例#12
0
def rename_logic( static_rules,
                  cur_state,
                  last_state,
                  old_state ):
    """
    Core logic of renaming the current state based on the rules and past state.
    This function assumes all inputs have been suitably sanitised.
    @param static_rules
        List of MACPCI objects representing rules
    @param cur_state
        List of MACPCI objects representing the current state
    @param last_state
        List of MACPCI objects representing the last boot state
    @param old_state
        List of MACPCI objects representing the old state
    @returns List of tuples...
    @throws AssertionError (Should not be thrown, but better to know about logic
    errors if they occur)
    """

    transactions = []

    if not len(cur_state):
        # If there are no nics present on the system, no renaming to perform
        return transactions

    # Certain drivers advertise multiple eth devices for the same PCI function
    # To avoid breaking the logic later, we need to know which PCI functions
    # have multiple eths.  As this is a per-driver effect, calculate it only
    # from the current state and not any saved state.
    multinic_functions = set()
    pci_functions = set()
    for nic in cur_state:
        if nic.pci in pci_functions:
            multinic_functions.add(nic.pci)
        else:
            pci_functions.add(nic.pci)
    if len(multinic_functions):
        LOG.debug("Detected the following PCI functions with multiple nics\n%s"
                  % (util.niceformat(multinic_functions),))

    # 1st pass.  Force current state into line according to the static rules
    for rule in static_rules:
        LOG.debug("Considering static rule '%s'" % (rule,))

        try:
            nic = cur_state[cur_state.index(rule)]
        except ValueError:
            LOG.debug("Static rule does not reference a current nic")
            continue

        __rename_nic(nic, rule.tname, transactions, cur_state)

    LOG.debug("Finished static rules. Transactions are \n%s\n"
              "Current State is \n%s" % (util.niceformat(transactions),
                                         util.niceformat(cur_state)))

    # 2nd pass. This logic should cover nics referenced by last or old state
    for nic in filter(util.needs_renaming, cur_state):
        LOG.info("Considering '%s'" % (nic,))

        # Did this nic appear in the same pci location as last boot?
        try:
            lastnic = last_state[last_state.index(nic)]
        except ValueError:
            # No it did not appear in the same location as before
            pass
        else:
            can_rename = util.tname_free(cur_state, lastnic.tname)

            # Warn if UDEV failed to rename the nic.  Either there is a logical
            # bug somewhere, or the user is messing around with our files.
            if VALID_ETH_NAME.match(nic.kname) is None:
                LOG.warning("nic '%s' in same location as last boot was not "
                            "renamed by udev." % (nic,))

            # Warn if UDEV did rename the nic, but not as per the last boot
            # information
            elif nic.kname != lastnic.tname:
                LOG.warning("nic '%s' in same location as last boot was "
                            "renamed by udev but to an unexpected name."
                            % (nic,))

            # It seems that UDEV is in order and it did successfully rename
            # the nic as instructed
            else:
                # If all is in order, and the nic currently has the same name
                # as it should end up having, fake a rename and make no
                # transactions for "ip link" to perform
                if can_rename:
                    LOG.info("nic '%s' in the same location as before. Keeping "
                             "it in the same location" % (nic,))
                    nic.tname = lastnic.tname
                    continue

            # If the correct target name is free, attempt to rename to it.
            if can_rename:
                LOG.info("nic '%s' in the same location as before but with a "
                         "wrong name.  Renaming to %s" % (nic, lastnic.tname))
                __rename_nic(nic, lastnic.tname, transactions, cur_state)
            else:
                # If the target name is already taken, warn about it
                LOG.warning("nic '%s' aliased from its last boot location. "
                            "Defering renaming and treating as new"
                            % (nic,))
            continue


        # if we saw this nic last time but its pci location is different, we
        # have just moved hardware on the bus so give it the old name
        lastnic = util.get_nic_with_mac(last_state, nic.mac)
        LOG.debug("nic_with_mac(last_state, %s) = %s" % (nic.mac, lastnic))
        if lastnic:
            LOG.info("nic '%s' moved on the pci bus from '%s'"
                     % (nic, lastnic))
            __rename_nic(nic, lastnic.tname, transactions, cur_state)
            continue

        # else this mac was not seen last boot. Is it on a multinic function?
        if nic.pci in multinic_functions:
            # if it is on a multinic_function, consider it brand new and rename
            # later
            LOG.info("nic '%s' is on a multinic pci function. Considering it "
                     "new and renaming later" % (nic,))
            continue

        # this nic is not on a multinic function.  Has it displaced another nic?
        lastnic = util.get_nic_with_pci(last_state+old_state, nic.pci)
        LOG.debug("nic_with_pci(last_state+old_state, %s) = %s"
                  % (nic.mac, lastnic))
        if lastnic:
            # This nic is in the place of an older nic.  Is that older nic still
            # present elsewhere in the system?
            if util.get_nic_with_mac(cur_state, lastnic.mac) is not None:
                # Yes - the displaced nic is still preset.  Therefore, that nic
                # has moved and this current nic is new.
                LOG.info("nic '%s' displaced older nic '%s' which is still "
                         "present.  Considering this nic new" % (nic, lastnic))
                continue
            else:
                # No - the displaced nic is no longer present so consider it
                # replaced
                LOG.info("nic '%s' has replaced older nic '%s'"
                         % (nic, lastnic))
                __rename_nic(nic, lastnic.tname, transactions, cur_state)
                continue

        # have we ever seen this nic before?
        lastnic = util.get_nic_with_mac(old_state, nic.mac)
        LOG.debug("nic_with_mac(old_state, %s) = %s" % (nic.mac, lastnic))
        if lastnic:
            # Yes - this nic was once present but not present last boot
            # Is its old name still availble?
            if util.tname_free(cur_state, lastnic.tname):
                # Old name is available - give it its old name back
                LOG.info("old nic '%s' returned and its name is free"
                         % (nic,))
                __rename_nic(nic, lastnic.tname, transactions, cur_state)
                continue
            else:
                LOG.info("old nic '%s' returned but its name is taken. "
                         "Treating it as new" % (nic,))
                continue

        LOG.info("nic '%s' seems brand new.  Defering until later for renaming"
                 % (nic,))


    LOG.debug("Finished dynamic rules. Transactions are \n%s\n"
              "Current State is \n%s" % (util.niceformat(transactions),
                                         util.niceformat(cur_state)))

    # 3rd pass.  This logic should cover multi-nic functions
    if len(multinic_functions):

        for fn in multinic_functions:
            lastnics = util.get_nics_with_pci(last_state + old_state, fn)
            newnics  = util.get_nics_with_pci(cur_state, fn)

            # Check that the function still has the same number of nics
            if len(lastnics) != len(newnics):
                LOG.warn("multi-nic function %s had %d nics but now has %d.  "
                         "Defering all until later for renaming"
                         % (fn, len(lastnics), len(newnics)))
                continue

            # Check that all nics are still pending a rename
            if False in (util.needs_renaming(n) for n in newnics):
                LOG.info("Some of %s's nics have alrealdy been renamed.  "
                         "Defering the rest until later for renaming"
                         % (fn, ))
                continue

            # Check that all expected target names are free
            if False in (util.tname_free(cur_state, n.tname) for n in lastnics):
                LOG.info("Some of %s's nics target names already used.  "
                         "Defering the rest until later for renaming"
                         % (fn, ))
                continue

            # Assume the MACs are ordered reliably.  They are typically adjacent
            lastnics.sort(key = lambda n: n.mac.integer)
            newnics.sort(key = lambda n: n.mac.integer)

            for new, old in zip(newnics, lastnics):
                __rename_nic(new, old.tname, transactions, cur_state)

        LOG.debug("Finished multi-nic logic.  Transactions are \n%s\n"
                  "Current State is \n%s" % (util.niceformat(transactions),
                                             util.niceformat(cur_state)))

    # For completely new network cards which we have never seen before, work out
    # a safe new number to assign it
    ethnumbers = sorted(
        map(lambda x: int(x[3:]),
            filter(lambda x: VALID_ETH_NAME.match(x) is not None,
                   map(lambda x: x.tname or x.kname,
                       static_rules + cur_state + last_state))))
    if len(ethnumbers):
        nextethnum = ethnumbers[-1]+1
    else:
        nextethnum = 0


    # 3rd pass. This should only affect brand new network cards unreferenced
    # by previous state.  Prefer the order (e.g. from biosdevname), given
    # no other objections.
    for nic in sorted(filter(util.needs_renaming, cur_state),
                      key=lambda x: x.order):
        LOG.info("Renaming brand new nic '%s'" % (nic,))

        if ( VALID_ETH_NAME.match(nic.kname) is not None and
             nic.kname not in map(lambda x: x.tname, cur_state) ):
            # User has been messing around with state files but not the udev
            # rules.  If the eth name is still free, give it

            nic.tname = nic.kname
            # No transaction needed
            continue

        newname = "eth%d" % (nextethnum, )
        nextethnum += 1
        __rename_nic(nic, newname, transactions, cur_state)


    LOG.debug("Finished all logic. Transactions are \n%s\n"
              "Current State is \n%s" % (util.niceformat(transactions),
                                         util.niceformat(cur_state)))
    return transactions
示例#13
0
def rename_logic(static_rules, cur_state, last_state, old_state):
    """
    Core logic of renaming the current state based on the rules and past state.
    This function assumes all inputs have been suitably sanitised.
    @param static_rules
        List of MACPCI objects representing rules
    @param cur_state
        List of MACPCI objects representing the current state
    @param last_state
        List of MACPCI objects representing the last boot state
    @param old_state
        List of MACPCI objects representing the old state
    @returns List of tuples...
    @throws AssertionError (Should not be thrown, but better to know about logic
    errors if they occur)
    """

    transactions = []

    if not len(cur_state):
        # If there are no nics present on the system, no renaming to perform
        return transactions

    # Certain drivers advertise multiple eth devices for the same PCI function
    # To avoid breaking the logic later, we need to know which PCI functions
    # have multiple eths.  As this is a per-driver effect, calculate it only
    # from the current state and not any saved state.
    multinic_functions = set()
    pci_functions = set()
    for nic in cur_state:
        if nic.pci in pci_functions:
            multinic_functions.add(nic.pci)
        else:
            pci_functions.add(nic.pci)
    if len(multinic_functions):
        LOG.debug(
            "Detected the following PCI functions with multiple nics\n%s" %
            (util.niceformat(multinic_functions), ))

    # 1st pass.  Force current state into line according to the static rules
    for rule in static_rules:
        LOG.debug("Considering static rule '%s'" % (rule, ))

        try:
            nic = cur_state[cur_state.index(rule)]
        except ValueError:
            LOG.debug("Static rule does not reference a current nic")
            continue

        __rename_nic(nic, rule.tname, transactions, cur_state)

    LOG.debug("Finished static rules. Transactions are \n%s\n"
              "Current State is \n%s" %
              (util.niceformat(transactions), util.niceformat(cur_state)))

    # 2nd pass. This logic should cover nics referenced by last or old state
    for nic in filter(util.needs_renaming, cur_state):
        LOG.info("Considering '%s'" % (nic, ))

        # Did this nic appear in the same pci location as last boot?
        try:
            lastnic = last_state[last_state.index(nic)]
        except ValueError:
            # No it did not appear in the same location as before
            pass
        else:
            can_rename = util.tname_free(cur_state, lastnic.tname)

            # Warn if UDEV failed to rename the nic.  Either there is a logical
            # bug somewhere, or the user is messing around with our files.
            if VALID_CUR_STATE_KNAME.match(nic.kname) is None:
                LOG.warning("nic '%s' was not renamed by udev." % (nic, ))

            # If the correct target name is free, attempt to rename to it.
            if can_rename:
                LOG.info("nic '%s' in the same location as before. "
                         "Renaming to %s" % (nic, lastnic.tname))
                __rename_nic(nic, lastnic.tname, transactions, cur_state)
            else:
                # If the target name is already taken, warn about it
                LOG.warning("nic '%s' aliased from its last boot location. "
                            "Defering renaming and treating as new" % (nic, ))
            continue

        # if we saw this nic last time but its pci location is different, we
        # have just moved hardware on the bus so give it the old name
        lastnic = util.get_nic_with_mac(last_state, nic.mac)
        LOG.debug("nic_with_mac(last_state, %s) = %s" % (nic.mac, lastnic))
        if lastnic:
            LOG.info("nic '%s' moved on the pci bus from '%s'" %
                     (nic, lastnic))
            __rename_nic(nic, lastnic.tname, transactions, cur_state)
            continue

        # else this mac was not seen last boot. Is it on a multinic function?
        if nic.pci in multinic_functions:
            # if it is on a multinic_function, consider it brand new and rename
            # later
            LOG.info("nic '%s' is on a multinic pci function. Considering it "
                     "new and renaming later" % (nic, ))
            continue

        # this nic is not on a multinic function.  Has it displaced another nic?
        lastnic = util.get_nic_with_pci(last_state + old_state, nic.pci)
        LOG.debug("nic_with_pci(last_state+old_state, %s) = %s" %
                  (nic.mac, lastnic))
        if lastnic:
            # This nic is in the place of an older nic.  Is that older nic still
            # present elsewhere in the system?
            if util.get_nic_with_mac(cur_state, lastnic.mac) is not None:
                # Yes - the displaced nic is still preset.  Therefore, that nic
                # has moved and this current nic is new.
                LOG.info("nic '%s' displaced older nic '%s' which is still "
                         "present.  Considering this nic new" % (nic, lastnic))
                continue
            else:
                # No - the displaced nic is no longer present so consider it
                # replaced
                LOG.info("nic '%s' has replaced older nic '%s'" %
                         (nic, lastnic))
                __rename_nic(nic, lastnic.tname, transactions, cur_state)
                continue

        # have we ever seen this nic before?
        lastnic = util.get_nic_with_mac(old_state, nic.mac)
        LOG.debug("nic_with_mac(old_state, %s) = %s" % (nic.mac, lastnic))
        if lastnic:
            # Yes - this nic was once present but not present last boot
            # Is its old name still availble?
            if util.tname_free(cur_state, lastnic.tname):
                # Old name is available - give it its old name back
                LOG.info("old nic '%s' returned and its name is free" %
                         (nic, ))
                __rename_nic(nic, lastnic.tname, transactions, cur_state)
                continue
            else:
                LOG.info("old nic '%s' returned but its name is taken. "
                         "Treating it as new" % (nic, ))
                continue

        LOG.info(
            "nic '%s' seems brand new.  Defering until later for renaming" %
            (nic, ))

    LOG.debug("Finished dynamic rules. Transactions are \n%s\n"
              "Current State is \n%s" %
              (util.niceformat(transactions), util.niceformat(cur_state)))

    # 3rd pass.  This pass ensures that replaced multi-nic functions
    # are ordered the same as a the previous state, relative to MACs.
    #
    # New multi-nic functions get ordered below.
    if len(multinic_functions):

        for fn in multinic_functions:
            lastnics = util.get_nics_with_pci(last_state + old_state, fn)
            newnics = util.get_nics_with_pci(cur_state, fn)

            # Check that the function still has the same number of nics
            if len(lastnics) != len(newnics):
                LOG.warn("multi-nic function %s had %d nics but now has %d.  "
                         "Defering all until later for renaming" %
                         (fn, len(lastnics), len(newnics)))
                continue

            # Check that all nics are still pending a rename
            if False in (util.needs_renaming(n) for n in newnics):
                LOG.info("Some of %s's nics have alrealdy been renamed.  "
                         "Defering the rest until later for renaming" % (fn, ))
                continue

            # Check that all expected target names are free
            if False in (util.tname_free(cur_state, n.tname)
                         for n in lastnics):
                LOG.info("Some of %s's nics target names already used.  "
                         "Defering the rest until later for renaming" % (fn, ))
                continue

            # Assume the MACs are ordered reliably.  They are typically adjacent
            lastnics.sort(key=lambda n: n.mac.integer)
            newnics.sort(key=lambda n: n.mac.integer)

            for new, old in zip(newnics, lastnics):
                __rename_nic(new, old.tname, transactions, cur_state)

        LOG.debug("Finished multi-nic logic.  Transactions are \n%s\n"
                  "Current State is \n%s" %
                  (util.niceformat(transactions), util.niceformat(cur_state)))

    # There may be some new multinic functions.  We can't trust biosdevname's
    # order for these NICs, so for each NIC collect the reported "order" <n>
    # (derived directly from eth<n>) and sort them according to the MACs
    if len(multinic_functions):
        LOG.debug("New multi-nic logic - attempting to re-order")
        for fn in multinic_functions:
            newnics = util.get_nics_with_pci(
                filter(util.needs_renaming, cur_state), fn)
            orders = sorted(map(lambda x: x.order, newnics))
            newnics.sort(key=lambda n: n.mac.integer)
            for nic, neworder in zip(newnics, orders):
                LOG.debug("NIC '%s' getting new order '%s'" % (nic, neworder))
                nic.order = neworder

    # For completely new network cards which we have never seen before, work out
    # a safe new number to assign it
    ethnumbers = sorted(
        map(
            lambda x: int(x[3:]),
            filter(
                lambda x: VALID_ETH_NAME.match(x) is not None,
                map(lambda x: x.tname or x.kname,
                    static_rules + cur_state + last_state))))
    if len(ethnumbers):
        nextethnum = ethnumbers[-1] + 1
    else:
        nextethnum = 0

    # 4th pass. This should only affect brand new network cards unreferenced
    # by previous state.  Prefer the order (e.g. from biosdevname), given
    # no other objections.
    for nic in sorted(filter(util.needs_renaming, cur_state),
                      key=lambda x: x.order):
        LOG.info("Renaming brand new nic '%s'" % (nic, ))

        if (VALID_ETH_NAME.match(nic.kname) is not None
                and nic.kname not in map(lambda x: x.tname, cur_state)):
            # User has been messing around with state files but not the udev
            # rules.  If the eth name is still free, give it

            nic.tname = nic.kname
            # No transaction needed
            continue

        newname = "eth%d" % (nextethnum, )
        nextethnum += 1
        __rename_nic(nic, newname, transactions, cur_state)

    LOG.debug("Finished all logic. Transactions are \n%s\n"
              "Current State is \n%s" %
              (util.niceformat(transactions), util.niceformat(cur_state)))
    return transactions
示例#14
0
    def load_and_parse(self):
        """
        Parse the static rules file.
        Returns boolean indicating success or failure.
        """

        fd = None

        try:
            try:
                # If we were given a path, try opening and reading it
                if self.path:
                    if not pathexists(self.path):
                        LOG.error("Static rule file '%s' does not exist"
                                  % (self.path,))
                        return False
                    fd = open(self.path, "r")
                    raw_lines = fd.readlines()

                # else if we were given a file descriptor, just read it
                elif self.fd:
                    raw_lines = self.fd.readlines()

                # else there is nothing we can do
                else:
                    LOG.error("No source of data to parse")
                    return False

            except IOError, e:
                LOG.error("IOError while reading file: %s" % (e,))
                return False
        finally:
            # Ensure we alway close the file descriptor we opened
            if fd:
                fd.close()

        # Generator to strip blank lines and line comments
        lines = ( (n, l.strip()) for (n, l) in enumerate(raw_lines)
                  if (len(l.strip()) and l.strip()[0] != '#') )


        for num, line in lines:
            # Check the line is valid
            res = VALID_LINE.match(line)
            if res is None:
                LOG.warning("Unrecognised line '%s' in static rules (line %d)"
                            % (line, num))
                continue

            groups = res.groupdict()

            target = groups["target"].strip()

            if groups["method"] is None:
                # As method is optional, set to 'guess' if not present
                method = "guess"
                LOG.debug("Guessing method for interface %s on line %d"
                          % (target, num) )
            else:
                method = groups["method"].strip()

            value = groups["val"].strip()
            if value[0] == value[-1] and value[0] in ("'", '"'):
                value = value[1:-1]
                # If we should guess the value, quotes imply a label
                if value == "guess":
                    value = "label"

            # Check that it is a recognised method
            if method not in StaticRules.methods:
                LOG.warning("Unrecognised static identification method "
                            "'%s' on line %d - Ignoring" % (method, num))
                continue

            # If we need to guess the method from the value
            if method == "guess":
                for k, v in StaticRules.validators.iteritems():
                    if v.match(value) is not None:
                        method = k
                        break
                else:
                    # If no validators, assume label
                    method = "label"

            # If we have a validator, test the valididy
            else:
                if method in StaticRules.validators:
                    if StaticRules.validators[method].match(value) is None:
                        LOG.warning("Invalid %s value '%s' on line %d - Ignoring"
                                    % (method, value, num))
                        continue

            # Warn if aliasing a previous static rule
            if target in self.formulae:
                LOG.warning("Static rule for '%s' already found.  Discarding "
                            "older entry" % (target,))

            # CA-82901 - Accept old-style ppns (pciXpY), but translate to
            # new-style ones (pXpY)
            if method == "ppn" and value.startswith("pci"):
                value = "p" + value[3:]
                LOG.warning("Detected use of old-style ppn reference for %s "
                            "on line %d - Translating to %s"
                            % (target, num, value) )

            self.formulae[target] = (method, value)

        return True
示例#15
0
                if ppn_quirks:
                    LOG.info("Not considering formula for '%s' due to ppn "
                             "quirks" % (target,))
                    continue

                for nic in state:
                    if nic.ppn == value:
                        try:
                            rule = MACPCI(nic.mac, nic.pci, tname=target)
                        except Exception, e:
                            LOG.warning("Error creating rule: %s" % (e,))
                            continue
                        self.rules.append(rule)
                        break
                else:
                    LOG.warning("No NIC found with a ppn of '%s' for the "
                                "%s static rule" % (value, target))
                continue

            elif method == "pci":

                for nic in state:
                    if nic.pci == value:
                        try:
                            rule = MACPCI(nic.mac, nic.pci, tname=target)
                        except Exception, e:
                            LOG.warning("Error creating rule: %s" % (e,))
                            continue
                        self.rules.append(rule)
                        break
                else:
                    LOG.warning("No NIC found with a PCI ID of '%s' for the "
示例#16
0
    def load_and_parse(self):
        """
        Parse the dynamic rules file.
        Returns boolean indicating success or failure.
        """

        fd = None

        try:
            try:
                # If we were given a path, try opening and reading it
                if self.path:
                    if not pathexists(self.path):
                        LOG.error("Dynamic rule file '%s' does not exist"
                                  % (self.path,))
                        return False
                    fd = open(self.path, "r")
                    raw_lines = fd.readlines()

                # else if we were given a file descriptor, just read it
                elif self.fd:
                    raw_lines = self.fd.readlines()

                # else there is nothing we can do
                else:
                    LOG.error("No source of data to parse")
                    return False

            except IOError, e:
                LOG.error("IOError while reading file: %s" % (e,))
                return False
        finally:
            # Ensure we alway close the file descriptor we opened
            if fd:
                fd.close()

        # Strip out line comments
        data = "\n".join([ l.strip() for l in raw_lines
                           if len(l.strip()) and l.strip()[0] != '#' ]
                         )

        # If the data is empty, dont pass it to json
        if not len( data.strip() ):
            return True

        try:
            info = json.loads(data)
        except ValueError:
            LOG.warning("Dynamic rules appear to be corrupt")
            return False
        # The installer has no json.
        except NameError:
            LOG.warning("Module json not available.  Cant parse dynamic rules.")
            return False

        if "lastboot" in info:
            for entry in info["lastboot"]:
                try:
                    if len(entry) != 3:
                        raise ValueError("Expected 3 entries")
                    macpci = MACPCI(entry[0], entry[1], tname=entry[2])
                except (TypeError, ValueError), e:
                    LOG.warning("Invalid lastboot data entry: %s"
                                % (e,))
                    continue
                self.lastboot.append(macpci)
示例#17
0
def ip_link_set_name(src_name, dst_name):
    """
    Rename network interface src_name to dst_name using
      "ip link set $src_name name $dst_name"
    """

    LOG.debug("Attempting rename %s -> %s" % (src_name, dst_name))

    # Is the interface currently up?
    link_show = Popen(["ip", "link", "show", src_name], stdout = PIPE)
    stdout, _ = link_show.communicate()

    if link_show.returncode != 0:
        LOG.error("performing \"ip link show %s\" returned %d - skipping"
                  % (src_name, link_show.returncode))
        return

    # Does the string "UP" appear?
    isup = 'UP' in (stdout.split("<", 1)[1].split(">", 1)[0].split(','))

    # If it is up, bring it down for the rename
    if isup:
        link_down = Popen(["ip", "link", "set", src_name, "down"])
        link_down.wait()

        if link_down.returncode != 0:
            LOG.error("Unable to bring link %s down. (Exit %d)"
                      % (src_name, link_down.returncode))
            return

    # Perform the rename
    link_rename = Popen(["ip", "link", "set", src_name, "name", dst_name])
    link_rename.wait()

    if link_rename.returncode != 0:
        LOG.error("Unable to rename link %s to %s. (Exit %d)"
                  % (src_name, dst_name, link_rename.returncode))
        return

    # if the device was up before, bring it back up
    if isup:

        # Performace note: if we are doing an intermediate rename to
        # move a device sideways, we shouldnt bring it back until it has
        # its final name.  However, i cant think of a non-hacky way of doing
        # this with the current implementation

        link_up = Popen(["ip", "link", "set", dst_name, "up"])
        link_up.wait()

        if link_up.returncode != 0:
            LOG.error("Unable to bring link %s back up. (Exit %d)"
                      % (src_name, link_down.returncode))
            return

    LOG.info("Succesfully renamed link %s to %s" % (src_name, dst_name))
示例#18
0
    def load_and_parse(self):
        """
        Parse the static rules file.
        Returns boolean indicating success or failure.
        """

        fd = None

        try:
            try:
                # If we were given a path, try opening and reading it
                if self.path:
                    if not pathexists(self.path):
                        LOG.error("Static rule file '%s' does not exist" %
                                  (self.path, ))
                        return False
                    fd = open(self.path, "r")
                    raw_lines = fd.readlines()

                # else if we were given a file descriptor, just read it
                elif self.fd:
                    raw_lines = self.fd.readlines()

                # else there is nothing we can do
                else:
                    LOG.error("No source of data to parse")
                    return False

            except IOError, e:
                LOG.error("IOError while reading file: %s" % (e, ))
                return False
        finally:
            # Ensure we alway close the file descriptor we opened
            if fd:
                fd.close()

        # Generator to strip blank lines and line comments
        lines = ((n, l.strip()) for (n, l) in enumerate(raw_lines)
                 if (len(l.strip()) and l.strip()[0] != '#'))

        for num, line in lines:
            # Check the line is valid
            res = VALID_LINE.match(line)
            if res is None:
                LOG.warning(
                    "Unrecognised line '%s' in static rules (line %d)" %
                    (line, num))
                continue

            groups = res.groupdict()

            target = groups["target"].strip()

            if groups["method"] is None:
                # As method is optional, set to 'guess' if not present
                method = "guess"
                LOG.debug("Guessing method for interface %s on line %d" %
                          (target, num))
            else:
                method = groups["method"].strip()

            value = groups["val"].strip()
            if value[0] == value[-1] and value[0] in ("'", '"'):
                value = value[1:-1]
                # If we should guess the value, quotes imply a label
                if value == "guess":
                    value = "label"

            # Check that it is a recognised method
            if method not in StaticRules.methods:
                LOG.warning("Unrecognised static identification method "
                            "'%s' on line %d - Ignoring" % (method, num))
                continue

            # If we need to guess the method from the value
            if method == "guess":
                for k, v in StaticRules.validators.iteritems():
                    if v.match(value) is not None:
                        method = k
                        break
                else:
                    # If no validators, assume label
                    method = "label"

            # If we have a validator, test the valididy
            else:
                if method in StaticRules.validators:
                    if StaticRules.validators[method].match(value) is None:
                        LOG.warning(
                            "Invalid %s value '%s' on line %d - Ignoring" %
                            (method, value, num))
                        continue

            # Warn if aliasing a previous static rule
            if target in self.formulae:
                LOG.warning("Static rule for '%s' already found.  Discarding "
                            "older entry" % (target, ))

            # CA-82901 - Accept old-style ppns (pciXpY), but translate to
            # new-style ones (pXpY)
            if method == "ppn" and value.startswith("pci"):
                value = "p" + value[3:]
                LOG.warning("Detected use of old-style ppn reference for %s "
                            "on line %d - Translating to %s" %
                            (target, num, value))

            self.formulae[target] = (method, value)

        return True
示例#19
0
                if ppn_quirks:
                    LOG.info("Not considering formula for '%s' due to ppn "
                             "quirks" % (target,))
                    continue

                for nic in state:
                    if nic.ppn == value:
                        try:
                            rule = MACPCI(nic.mac, nic.pci, tname=target)
                        except Exception, e:
                            LOG.warning("Error creating rule: %s" % (e,))
                            continue
                        self.rules.append(rule)
                        break
                else:
                    LOG.warning("No NIC found with a ppn of '%s' for the "
                                "%s dynamic rule" % (value, target))
                continue

            elif method == "pci":

                for nic in state:
                    if nic.pci == value:
                        try:
                            rule = MACPCI(nic.mac, nic.pci, tname=target)
                        except Exception, e:
                            LOG.warning("Error creating rule: %s" % (e,))
                            continue
                        self.rules.append(rule)
                        break
                else:
                    LOG.warning("No NIC found with a PCI ID of '%s' for the "