From 72ae585dea21cd2355a9e47e03f4e96c5b850127 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 11 Apr 2014 14:42:00 +0100 Subject: [PATCH] Introduce a server subclass to hold network name and address information Signed-off-by: David Howells --- suite/commands/vos/listaddrs.py | 4 +- suite/commands/vos/listvldb.py | 2 +- suite/lib/addrcache.py | 72 ++++++++++++++++++++++--- suite/lib/cell.py | 7 +-- suite/lib/fileserver.py | 36 ++----------- suite/lib/server.py | 94 +++++++++++++++++++++++++++++++++ suite/lib/vlserver.py | 39 ++------------ suite/lib/volserver.py | 38 ++----------- 8 files changed, 179 insertions(+), 113 deletions(-) create mode 100644 suite/lib/server.py diff --git a/suite/commands/vos/listaddrs.py b/suite/commands/vos/listaddrs.py index c450f5b..9eee7c3 100644 --- a/suite/commands/vos/listaddrs.py +++ b/suite/commands/vos/listaddrs.py @@ -31,7 +31,7 @@ help = "Display all VLDB entries" command_arguments = [ [ "uuid", get_uuid, "os", "" ], - [ "host", get_dummy, "os", "
" ], + [ "host", get_fileserver, "os", "
" ], [ "printuuid", get_dummy, "fn" ], [ "cell", get_cell, "os", "" ], [ "noauth", get_auth, "fn" ], @@ -98,6 +98,6 @@ def main(params): attributes.uuid = params["uuid"] if "host" in params: attributes.Mask |= kafs.VLADDR_IPADDR - attributes.ipaddr = addrcache.name2addr_int(params["host"][0]) + attributes.ipaddr = params["host"].integer_addr() list_one(params, vl_conn, attributes) diff --git a/suite/commands/vos/listvldb.py b/suite/commands/vos/listvldb.py index 354bf43..51ec8de 100644 --- a/suite/commands/vos/listvldb.py +++ b/suite/commands/vos/listvldb.py @@ -81,7 +81,7 @@ def main(params): if "server" in params: attributes.Mask |= kafs.VLLIST_SERVER - attributes.server = addrcache.name2addr_int(str(params["server"])) + attributes.server = params["server"].integer_addr() if "partition" in params: attributes.Mask |= kafs.VLLIST_PARTITION attributes.partition = params["partition"] diff --git a/suite/lib/addrcache.py b/suite/lib/addrcache.py index 6cfb4d9..926b38b 100644 --- a/suite/lib/addrcache.py +++ b/suite/lib/addrcache.py @@ -40,7 +40,12 @@ def add(name, addr): cache_n2a[name].append(addr) cache_a2n[addr] = name -def name2addr(name): +############################################################################### +# +# Convert a name to an array of addresses in string form (eg. "1.2.3.4"). +# +############################################################################### +def name2addrs(name): # Try parsing as a numeric IPv4 address try: addr = inet_pton(AF_INET, name) @@ -67,6 +72,36 @@ def name2addr(name): return cache_n2a[name] +############################################################################### +# +# Convert a string address to an address in integer form +# +############################################################################### +def addr2addr_int(name): + # Try parsing as a numeric IPv4 address + try: + addr = inet_pton(AF_INET, name) + inaddr = addr[0] << 24 + inaddr |= addr[1] << 16 + inaddr |= addr[2] << 8 + inaddr |= addr[3] << 0 + return inaddr + except OSError: + pass + + # Try parsing as a numeric IPv6 address + try: + addr = inet_pton(AF_INET6, name) + raise NetAddressError("IPv6 is not currently supported") + except OSError: + pass + raise NetAddressError("Can't translate '" + name + "' to integer") + +############################################################################### +# +# Convert a name or string address to an address in integer form +# +############################################################################### def name2addr_int(name): # Try parsing as a numeric IPv4 address try: @@ -95,20 +130,37 @@ def name2addr_int(name): inaddr |= addr[3] << 0 return inaddr -def addr2name(addr): - if addr not in cache_a2n: +############################################################################### +# +# Convert one of a set of presumably synonymous addresses to a name. We assume +# that this will be an N:1 mapping. +# +############################################################################### +def addrs2name(addrs): + for addr in addrs: + if addr in cache_a2n: + return cache_a2n[addr] + + for addr in addrs: try: revname = dns.reversename.from_address(addr) for PTR in dns.resolver.query(revname, 'PTR'): name = str(PTR).lower().rstrip(".") add(name, addr) return name - - return None except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN): - return None - return cache_a2n[addr] + pass + + return None + +def addr2name(addr): + return addrs2name([ addr ]) +############################################################################### +# +# Convert an integer address to a string address. +# +############################################################################### def int2addr(i): inaddr = bytearray(4) inaddr[0] = (i >> 24) & 0xff @@ -117,6 +169,12 @@ def int2addr(i): inaddr[3] = (i >> 0) & 0xff return inet_ntoa(bytes(inaddr)) +############################################################################### +# +# Resolve an integer or string address to a string address or a name, +# depending on whether "noresolve" is set. +# +############################################################################### def resolve(params, addr): if str(type(addr)) == "": addr = int2addr(addr) diff --git a/suite/lib/cell.py b/suite/lib/cell.py index d9a1cdf..7aa2e35 100644 --- a/suite/lib/cell.py +++ b/suite/lib/cell.py @@ -22,7 +22,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ from afs import exception -from afs.lib.vlserver import vlserver, VLServerError +from afs.lib.vlserver import vlserver +from afs.lib.server import ServerError from afs.lib.debug import debug import dns.resolver import linecache @@ -110,7 +111,7 @@ class cell: for j in i.addrs(): if j not in addrs: addrs.append(j) - except VLServerError: + except ServerError: pass if len(addrs) == 0: @@ -163,7 +164,7 @@ class cell: def open_volume_server(self, server, params=None): key, security = self.determine_security(params) - debug("Trying", server) + debug("Trying", server.addr()) vol_conn = kafs.rx_new_connection(server.addr(), kafs.VOLSERVICE_PORT, kafs.VOLSERVICE_ID, diff --git a/suite/lib/fileserver.py b/suite/lib/fileserver.py index 2a7c6ee..30d57ae 100644 --- a/suite/lib/fileserver.py +++ b/suite/lib/fileserver.py @@ -22,42 +22,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ from afs import exception -import afs.lib.addrcache as addrcache from afs.lib.debug import debug -import dns.resolver +from afs.lib.server import server -class FileServerError(exception.AFSException): - """Error raised by L{fileserver} objects.""" - -class fileserver: +class fileserver(server): """Represents an AFS File server. We hold the server address here.""" def __init__(self, name): debug("New FileServer", name) - self.__name = name - self.__looked_up = False - - # We want to maintain the record order provided by the DNS to entry - # force rotation, so we don't want to use an unordered set here. - # - # Note that the addrs are stored as text strings of the form "a.b.c.d" - self.__addrs = [] + server.__init__(self, name) def __repr__(self): - return "<" + "AFSFS:" + self.__name + ">" - - def __str__(self): - return self.__name - - def look_up_addresses(self): - self.__addrs = addrcache.name2addr(self.__name) - self.__looked_up = True - - def look_up(self): - if not self.__looked_up: - self.look_up_addresses() - if len(self.__addrs) == 0: - raise FileServerError("No FileServer addresses available") - return self.__addrs - - def addrs(self): - return self.look_up() + return "<" + "AFSFS:" + server.__str_(self) + ">" diff --git a/suite/lib/server.py b/suite/lib/server.py new file mode 100644 index 0000000..8552d08 --- /dev/null +++ b/suite/lib/server.py @@ -0,0 +1,94 @@ +# +# AFS Volume management toolkit: Server record +# -*- coding: utf-8 -*- +# + +__copyright__ = """ +Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. +Written by David Howells (dhowells@redhat.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public Licence version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public Licence for more details. + +You should have received a copy of the GNU General Public Licence +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +from afs import exception +import afs.lib.addrcache as addrcache +from afs.lib.debug import debug +from socket import inet_pton, inet_ntoa, AF_INET, AF_INET6; + +class ServerError(exception.AFSException): + """Error raised by L{volserver} objects.""" + +class server: + """Represents the name and addresses of a server on the network.""" + def __init__(self, name): + self.__name = None + self.__addrs4 = None + self.__addrs6 = None + self.__inaddr = None + + if str(type(name)) == "": + self.__addrs4 = [ addrcache.int2addr(name) ] + else: + # Try parsing as a numeric IPv4 address + try: + self.__addrs4 = [ inet_pton(AF_INET, name) ] + except OSError: + # Try parsing as a numeric IPv6 address + try: + self.__addrs6 = [ inet_pton(AF_INET6, name) ] + raise NetAddressError("IPv6 is not currently supported") + except OSError: + self.__name = name + + def __repr__(self): + if self.__name != None: + name = self.__name + else: + name = self.__addrs4[0] + return "<" + "server:" + name + ">" + + def __str__(self): + if self.__name != None: + name = self.__name + else: + name = self.__addrs4[0] + return name + + def look_up_name(self): + if self.__name == None: + self.__name = addrcache.addrs2name(self.__addrs4) + if self.__name == None: + self.__name = self.__addrs4[0] + return self.__name + + def look_up_addresses(self): + if self.__addrs4 == None: + self.__addrs4 = addrcache.name2addrs(self.__name) + if len(self.__addrs4) == 0: + raise ServerError("No addresses available for '" + self.__name + "'") + return self.__addrs4 + + def name(self): + return self.look_up_name() + + def addrs(self): + return self.look_up_addresses() + + def addr(self): + return self.look_up_addresses()[0] + + def integer_addr(self): + if self.__inaddr == None: + self.__inaddr = addrcache.addr2addr_int(self.look_up_addresses()[0]) + return self.__inaddr diff --git a/suite/lib/vlserver.py b/suite/lib/vlserver.py index cf75631..602f889 100644 --- a/suite/lib/vlserver.py +++ b/suite/lib/vlserver.py @@ -22,43 +22,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ from afs import exception -import afs.lib.addrcache as addrcache from afs.lib.debug import debug -from socket import inet_pton, AF_INET, AF_INET6; -import dns.resolver +from afs.lib.server import server -class VLServerError(exception.AFSException): - """Error raised by L{vlserver} objects.""" - -class vlserver: +class vlserver(server): """Represents an AFS Volume Location server. We hold the server address here.""" def __init__(self, name): - debug("New VLServer", name) - self.__name = name - self.__looked_up = False - - # We want to maintain the record order provided by the DNS to entry - # force rotation, so we don't want to use an unordered set here. - # - # Note that the addrs are stored as text strings of the form "a.b.c.d" - self.__addrs = [] + debug("New VolServer", name) + server.__init__(self, name) def __repr__(self): - return "<" + "AFSVL:" + self.__name + ">" - - def __str__(self): - return self.__name - - def look_up_addresses(self): - self.__addrs = addrcache.name2addr(self.__name) - self.__looked_up = True - - def look_up(self): - if not self.__looked_up: - self.look_up_addresses() - if len(self.__addrs) == 0: - raise VLServerError("No VLServer addresses available") - return self.__addrs - - def addrs(self): - return self.look_up() + return "<" + "AFSVL:" + server.__str_(self) + ">" diff --git a/suite/lib/volserver.py b/suite/lib/volserver.py index a35c963..3daf809 100644 --- a/suite/lib/volserver.py +++ b/suite/lib/volserver.py @@ -22,44 +22,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ from afs import exception -import afs.lib.addrcache as addrcache from afs.lib.debug import debug -import dns.resolver +from afs.lib.server import server -class VolServerError(exception.AFSException): - """Error raised by L{volserver} objects.""" - -class volserver: +class volserver(server): """Represents an AFS Volume server. We hold the server address here.""" def __init__(self, name): - if str(type(name)) == "": - name = addrcache.int2addr(name) debug("New VolServer", name) - self.__name = name - self.__looked_up = False - - # We want to maintain the record order provided by the DNS to entry - # force rotation, so we don't want to use an unordered set here. - # - # Note that the addrs are stored as text strings of the form "a.b.c.d" - self.__addrs = [] + server.__init__(self, name) def __repr__(self): - return "<" + "AFSFS:" + self.__name + ">" - - def __str__(self): - return self.__name - - def look_up_addresses(self): - self.__addrs = addrcache.name2addr(self.__name) - self.__looked_up = True - - def look_up(self): - if not self.__looked_up: - self.look_up_addresses() - if len(self.__addrs) == 0: - raise VolServerError("No VolServer addresses available") - return self.__addrs - - def addr(self): - return self.look_up()[0] + return "<" + "AFSVOL:" + server.__str_(self) + ">" -- 2.50.1