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
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
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
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
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
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
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
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))
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))
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
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
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
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
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
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 "
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)
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))
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
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 "