Module srboo |
[hide private]
[frames] | no frames]

## Source Code for Module srboo

      1
      2  ################################################################
      3  #
      4  # Description: Object Oriented wrapper to Python SRB Interface
      5  # Author:      Rob Sanderson (azaroth@liv.ac.uk)
      6  # Date:        2005-05-12
      7  # Version:     0.8
      8  # Copyright:   (c) University of Liverpool
      9  # Licence:     GPL
     10  #
     11  ################################################################
     12
     13
     14  import srb
     15  import types
     16  import socket
     17  import atexit
     18  from srbErrors import errmsgs
     19
     20
     21  # To Do:
     22  # !! Will fail at greater than MAX_GET_RESULT objects per collection
     23
     24
     25  # Ensure polite disconnect behaviour
     26  connections = []
     27 -def disconnect_all():
     28      for c in connections:
     29          try:
     30              c.disconnect()
     31          except:
     32              pass
     33  atexit.register(disconnect_all)
     34
     35
     36 -class SrbException(Exception):
     37 -    def __init__(self, type, info=""):
     38          self.type = type
     39          self.message = errmsgs[type]
     40          self.info = info
     41
     42 -    def __repr__(self):
     43          return "<<SrbException: (%s) %s>>" % (self.message, self.info)
     44 -    def __str__(self):
     45          return "<<SrbException: (%s) %s>>" % (self.message, self.info)
     46
     47
     48
     49 -class SrbFile(object):
     50      conn = None
     51      fd = -1
     52      name = ""
     53      collection = ""
     54      # Maybe store index in collection?
     55      # For wrapper to get non-name metadata
     56      position = 0
     57
     58 -    def __init__(self, conn, name):
     59          self.conn = conn
     60          self.name = name
     61          if not conn.collection:
     62              raise TypeError("Connection does not have a collection set.")
     63          else:
     64              self.collection = conn.collection
     65
     66
     67 -    def _connect(self, flag):
     68          fd = srb.obj_open(self.conn.id, self.collection, self.name, flag)
     69          if (fd < 0):
     70              raise SrbException(fd, "Failed to open %s" % self.name)
     71          else:
     72              self.fd = fd
     73
     74 -    def _create(self, size, resource, type, path):
     75          fd = srb.obj_create(self.conn.id, 0, self.name, type, resource,
     76                              self.collection, path, size)
     77          if fd < 0:
     78              raise SrbException(fd, "Failed to create %s" % self.name)
     79          else:
     80              self.fd = fd
     81
     82 -    def fileno(self):
     83          return self.fd
     84
     85 -    def isatty(self):
     86          return False
     87
     88 -    def flush(self):
     89          # SRB auto flushes
     90          return None
     91
     92 -    def tell(self):
     93          return self.position
     94
     95 -    def read(self, size=-1):
     96          if self.fd < 0:
     97              raise TypeError('File is not open.')
     98          if size > -1:
     99              data = srb.obj_read(self.conn.id, self.fd, size)
    100              self.position += size
    101          else:
    102              data = ""
    103              while 1:
    104                  buffer = srb.obj_read(self.conn.id, self.fd, 1024)
    105                  self.position += 1024
    106                  if buffer == "": break
    107                  data += buffer
    108          return data
    109
    110 -    def close(self):
    111          if self.fd < 0:
    112              raise TypeError('File is not open.')
    113          resp = srb.obj_close(self.conn.id, self.fd)
    114          if resp < 0:
    115              raise SrbException(resp)
    116          else:
    117              self.fd = -1
    118
    119 -    def write(self, value):
    120          if self.fd < 0:
    121              raise TypeError('File is not open.')
    122          #if type(value) == types.UnicodeType:
    123          #    try:
    124          #        value = value.encode('utf-8')
    125          #    except:
    126          #        raise TypeError("Cannot map unicode object to srb-writable string.")
    127          #elif type(value) != types.StringType:
    128          #    raise TypeError("Can only write strings to SRB")
    129
    130          resp = srb.obj_write(self.conn.id, self.fd, value, len(value))
    131          if resp < 0:
    132              raise SrbException(resp)
    133          else:
    134              return resp
    135
    136 -    def seek(self, offset, whence=0):
    137          if self.fd < 0:
    138              raise TypeError('File is not open.')
    139          resp = srb.obj_seek(self.conn.id, self.fd, offset, whence)
    140          if resp < 0:
    141              raise SrbException(resp)
    142          else:
    143              self.position = whence + offset
    144
    145 -    def delete(self, copynum=0):
    146          resp = srb.obj_delete(self.conn.id, self.name, copynum, self.collection)
    147          if resp < 0:
    148              raise SrbException(resp)
    149
    150 -    def get_umetadata(self):
    151          md = srb.get_user_metadata(self.conn.id, self.name, self.connection)
    152          if typeof(md) == types.IntType:
    153              if (md == -3005):
    154                  md = {}
    155              else:
    156                  raise SrbException(md)
    157          return md
    158
    159 -    def set_umetadata(self, f, v):
    160          try:
    161              self.delete_umetadata(f)
    162          except:
    163              pass
    164          status = srb.set_user_metadata(self.conn.id, self.name, self.collection, f, v)
    165          if status < 0:
    166              raise SrbException(status)
    167          else:
    168              return status
    169
    170 -    def delete_umetadata(self, f):
    171          md = self.get_umetadata()
    172          if (md.has_key(f)):
    173              status = srb.rm_user_metadata(self.conn.id, self.name, self.connection, f, md[f])
    174          else:
    175              status = 0
    176          if status < 0:
    177              raise SrbException(status)
    178          else:
    179              return status
    180
    181
    182 -class SrbConnection(object):
    183      id = -1
    184      collection = ""
    185      resource = ""
    186
    187      host = ""
    188      port = ""
    189      domain = ""
    190      auth = ""
    191      user = ""
    192      passwd = ""
    193      dn = ""
    194
    195 -    def __init__(self, host, port, domain, auth="ENCRYPT1", user="", passwd="", dn=""):
    196
    197          # Lookup host to ensure safe
    198          try:
    199              info = socket.gethostbyname(host)
    200              self.host = host
    201          except socket.gaierror, e:
    202              raise TypeError("Unknown host: %s" % host)
    203
    204          if type(port) == types.IntType:
    205              self.port = str(port)
    206          elif type(port) == types.StringType:
    207              if port.isdigit():
    208                  self.port = port
    209              else:
    210                  raise TypeError("Port must be numeric")
    211          else:
    212              raise TypeError("Port must be integer or numeric string")
    213
    214          self.domain = domain
    215
    216          if auth == "PASSWD_AUTH":
    217              # deprecated
    218              self.auth = "ENCRYPT1"
    219          elif auth in ["ENCRYPT1", "GSI_AUTH"]:
    220              self.auth = auth
    221          elif not auth and user and passwd:
    222              self.auth = "ENCRYPT1"
    223          elif not auth and dn:
    224              self.auth = "GSI_AUTH"
    225          else:
    226              print user, passwd
    227              raise TypeError("Unknown authentication type: %s" % auth)
    228
    229          assert self.host
    230          assert self.port
    231          assert self.domain
    232          if self.auth == "ENCRYPT1":
    233              assert user
    234              assert passwd
    235          elif self.auth == "GSI_AUTH":
    236              assert dn
    237
    238          sid = srb.connect(self.host, self.port, self.domain, self.auth, user, passwd, dn)
    239          if sid < 0:
    240              raise SrbException(sid)
    241          else:
    242              self.id = sid
    243              connections.append(self)
    244              self.open_collection("/home/%s.%s" % (user, domain))
    245
    246 -    def disconnect(self):
    247          srb.disconnect(self.id)
    248
    249 -    def open(self, name, flag='w'):
    250          # Map from 'r', 'a', 'w' to unixFlag int
    251          # XXX How to open at end for 'a' ?
    252          if flag == 'r':
    253              iflag = 0
    254          else:
    255              iflag = 2
    256          f = SrbFile(self, name)
    257          f._connect(iflag)
    258          return f
    259
    260 -    def create(self, name, size=-1, type="generic", resource="", path=""):
    261          f = SrbFile(self, name)
    262          if not resource and not self.resource:
    263              raise TypeError("Must either give resource or set on connection")
    264          elif not resource:
    265              resource = self.resource
    266          f._create(size, resource, type, path)
    267          return f
    268
    269 -    def create_collection(self, name):
    270          # Create collection in current
    271          resp = srb.mk_collection(self.id, 0, self.collection, name)
    272          if resp < 0:
    273              raise SrbException(resp)
    274
    275 -    def up_collection(self):
    276          new = self.collection[:self.collection.rindex('/')]
    277          self.open_collection(new)
    278
    279 -    def open_collection(self, name):
    280          if (name[0] != '/'):
    281              name = self.collection + '/' + name
    282          self.collection = name
    283          self.n_objects()
    284          self.n_subcollections()
    285
    286 -    def delete_collection(self, recursive=0):
    287          resp = srb.rm_collection(self.id, 0, recursive, self.collection)
    288          if resp < 0:
    289              raise SrbException(resp)
    290          else:
    291              self.up_collection()
    292
    293 -    def n_subcollections(self):
    294          n = srb.get_subcolls(self.id, 0, self.collection)
    295          if n < 0:
    296              raise SrbException(n)
    297          else:
    298              self.subcolls = n
    299              return n
    300
    301 -    def n_objects(self):
    302          # Order of objects by name
    303          n = srb.get_objs_in_coll(self.id, 0,2, self.collection)
    304          if n < 0:
    305              raise SrbException(n)
    306          else:
    307              self.objects = n
    308              return n
    309
    310 -    def object_metadata(self, idx, type='name'):
    311          # Will raise if not valid
    312          if not self.collection:
    313              raise TypeError("Must open a collection first")
    314          elif idx >= self.objects:
    315              raise IndexError("Object index out of range")
    316          t = ['name', 'collection', 'size', 'type', 'owner', 'timestamp', 'replica', 'resource'].index(type)
    317          return srb.get_obj_metadata(self.id, t, idx)
    318
    319 -    def collection_name(self, idx):
    320          if not self.collection:
    321              raise TypeError("Must open a collection first")
    322          elif idx >= self.subcolls:
    323              raise IndexError("Subcollection index out of range")
    324          return srb.get_subcoll_name(self.id, idx)
    325
    326
    327 -    def walk_names(self):
    328          # Return tuple of colls, files
    329          self.n_subcollections()
    330          self.n_objects()
    331          colls = []
    332          files = []
    333          for s in range(self.subcolls):
    334              colls.append(self.collection_name(s))
    335          for f in range(self.objects):
    336              files.append(self.object_metadata(f))
    337          return (colls, files)
    338
    339 -    def walk(self):
    340          # Following os.walk
    341          # (Leaves you in lowest leaf)
    342          (colls, files) = self.walk_names()
    343          yield self.collection, colls, files
    344          for name in colls:
    345              self.open_collection(name)
    346              for x in self.walk():
    347                  yield x
    348
    349
    350 -    def rmrf(self):
    351          for path, dirs, files in self.walk():
    352              for file in files:
    353                  f = self.open(file)
    354                  f.close()
    355                  f.delete()
    356