- re-enable return_fields specification
authorMark Huang <mlhuang@cs.princeton.edu>
Thu, 9 Nov 2006 19:43:57 +0000 (19:43 +0000)
committerMark Huang <mlhuang@cs.princeton.edu>
Thu, 9 Nov 2006 19:43:57 +0000 (19:43 +0000)
- since the primary key of each table may not be specified in
  return_fields, Table is now a list instead of a dict, which
  mirrors the actual return type of the Get() functions anyway

131 files changed:
PLC/AddressTypes.py
PLC/Addresses.py
PLC/Auth.py
PLC/ConfFiles.py
PLC/Events.py
PLC/ForeignNodes.py
PLC/Keys.py
PLC/Methods/AddAddressTypeToAddress.py
PLC/Methods/AddConfFileToNode.py
PLC/Methods/AddConfFileToNodeGroup.py
PLC/Methods/AddNode.py
PLC/Methods/AddNodeNetwork.py
PLC/Methods/AddNodeToNodeGroup.py
PLC/Methods/AddNodeToPCU.py
PLC/Methods/AddPCU.py
PLC/Methods/AddPersonKey.py
PLC/Methods/AddPersonToSite.py
PLC/Methods/AddPersonToSlice.py
PLC/Methods/AddRoleToPerson.py
PLC/Methods/AddSiteAddress.py
PLC/Methods/AddSlice.py
PLC/Methods/AddSliceAttribute.py
PLC/Methods/AddSliceToNodes.py
PLC/Methods/AdmDeleteAllPersonKeys.py
PLC/Methods/AdmDeletePersonKeys.py
PLC/Methods/AdmDisassociatePowerControlUnitPort.py
PLC/Methods/AdmGenerateNodeConfFile.py
PLC/Methods/AdmGetAllNodeNetworks.py
PLC/Methods/AdmGetNodeGroupNodes.py
PLC/Methods/AdmGetPersonKeys.py
PLC/Methods/AdmGetPersonRoles.py
PLC/Methods/AdmGetPersonSites.py
PLC/Methods/AdmGetPowerControlUnitNodes.py
PLC/Methods/AdmGetSiteNodes.py
PLC/Methods/AdmGetSitePIs.py
PLC/Methods/AdmGetSitePersons.py
PLC/Methods/AdmGetSitePowerControlUnits.py
PLC/Methods/AdmGetSiteTechContacts.py
PLC/Methods/AdmIsPersonInRole.py
PLC/Methods/AdmQueryConfFile.py
PLC/Methods/AdmQueryNode.py
PLC/Methods/AdmQueryPerson.py
PLC/Methods/AdmQueryPowerControlUnit.py
PLC/Methods/AdmQuerySite.py
PLC/Methods/BlacklistKey.py
PLC/Methods/BootGetNodeDetails.py
PLC/Methods/BootNotifyOwners.py
PLC/Methods/BootUpdateNode.py
PLC/Methods/DeleteAddress.py
PLC/Methods/DeleteAddressType.py
PLC/Methods/DeleteAddressTypeFromAddress.py
PLC/Methods/DeleteBootState.py
PLC/Methods/DeleteConfFile.py
PLC/Methods/DeleteConfFileFromNode.py
PLC/Methods/DeleteConfFileFromNodeGroup.py
PLC/Methods/DeleteKey.py
PLC/Methods/DeleteKeyType.py
PLC/Methods/DeleteMessage.py
PLC/Methods/DeleteNetworkMethod.py
PLC/Methods/DeleteNetworkType.py
PLC/Methods/DeleteNode.py
PLC/Methods/DeleteNodeFromNodeGroup.py
PLC/Methods/DeleteNodeFromPCU.py
PLC/Methods/DeleteNodeGroup.py
PLC/Methods/DeleteNodeNetwork.py
PLC/Methods/DeletePCU.py
PLC/Methods/DeletePerson.py
PLC/Methods/DeletePersonFromSite.py
PLC/Methods/DeletePersonFromSlice.py
PLC/Methods/DeleteRole.py
PLC/Methods/DeleteRoleFromPerson.py
PLC/Methods/DeleteSession.py
PLC/Methods/DeleteSite.py
PLC/Methods/DeleteSlice.py
PLC/Methods/DeleteSliceAttribute.py
PLC/Methods/DeleteSliceAttributeType.py
PLC/Methods/DeleteSliceFromNodes.py
PLC/Methods/DeleteSliceInstantiation.py
PLC/Methods/GetAddressTypes.py
PLC/Methods/GetAddresses.py
PLC/Methods/GetBootStates.py
PLC/Methods/GetConfFiles.py
PLC/Methods/GetEvents.py
PLC/Methods/GetForeignNodes.py
PLC/Methods/GetKeyTypes.py
PLC/Methods/GetKeys.py
PLC/Methods/GetMessages.py
PLC/Methods/GetNetworkMethods.py
PLC/Methods/GetNetworkTypes.py
PLC/Methods/GetNodeGroups.py
PLC/Methods/GetNodeNetworks.py
PLC/Methods/GetNodes.py
PLC/Methods/GetPCUs.py
PLC/Methods/GetPeers.py
PLC/Methods/GetPersons.py
PLC/Methods/GetRoles.py
PLC/Methods/GetSites.py
PLC/Methods/GetSliceAttributeTypes.py
PLC/Methods/GetSliceAttributes.py
PLC/Methods/GetSliceInstantiations.py
PLC/Methods/GetSlices.py
PLC/Methods/GetSlivers.py
PLC/Methods/RebootNode.py
PLC/Methods/RefreshPeer.py
PLC/Methods/SetPersonPrimarySite.py
PLC/Methods/UpdateAddress.py
PLC/Methods/UpdateAddressType.py
PLC/Methods/UpdateConfFile.py
PLC/Methods/UpdateKey.py
PLC/Methods/UpdateMessage.py
PLC/Methods/UpdateNode.py
PLC/Methods/UpdateNodeGroup.py
PLC/Methods/UpdateNodeNetwork.py
PLC/Methods/UpdatePCU.py
PLC/Methods/UpdatePerson.py
PLC/Methods/UpdateSite.py
PLC/Methods/UpdateSlice.py
PLC/Methods/UpdateSliceAttribute.py
PLC/Methods/UpdateSliceAttributeType.py
PLC/NodeGroups.py
PLC/NodeNetworks.py
PLC/Nodes.py
PLC/PCUs.py
PLC/Peers.py
PLC/Persons.py
PLC/Sessions.py
PLC/Sites.py
PLC/SliceAttributeTypes.py
PLC/SliceAttributes.py
PLC/Slices.py
PLC/Table.py

index 56319e2..19f9b16 100644 (file)
@@ -4,7 +4,7 @@
 # Mark Huang <mlhuang@cs.princeton.edu>
 # Copyright (C) 2006 The Trustees of Princeton University
 #
-# $Id: AddressTypes.py,v 1.7 2006/11/08 22:34:05 mlhuang Exp $
+# $Id: AddressTypes.py,v 1.8 2006/11/09 03:07:42 mlhuang Exp $
 #
 
 from types import StringTypes
@@ -46,11 +46,11 @@ class AddressTypes(Table):
     Representation of the address_types table in the database.
     """
 
-    def __init__(self, api, address_type_filter = None):
-       Table.__init__(self, api, AddressType)
+    def __init__(self, api, address_type_filter = None, columns = None):
+       Table.__init__(self, api, AddressType, columns)
 
         sql = "SELECT %s FROM address_types WHERE True" % \
-              ", ".join(AddressType.fields)
+              ", ".join(self.columns)
 
         if address_type_filter is not None:
             if isinstance(address_type_filter, (list, tuple, set)):
index b27cbd7..62f9e3b 100644 (file)
@@ -83,11 +83,11 @@ class Addresses(Table):
     database.
     """
 
-    def __init__(self, api, address_filter = None):
-       Table.__init__(self, api, Address)
+    def __init__(self, api, address_filter = None, columns = None):
+       Table.__init__(self, api, Address, columns)
 
         sql = "SELECT %s FROM view_addresses WHERE True" % \
-              ", ".join(Address.fields)
+              ", ".join(self.columns)
 
         if address_filter is not None:
             if isinstance(address_filter, (list, tuple, set)):
index 72e9d91..c186028 100644 (file)
@@ -4,7 +4,7 @@
 # Mark Huang <mlhuang@cs.princeton.edu>
 # Copyright (C) 2006 The Trustees of Princeton University
 #
-# $Id: Auth.py,v 1.6 2006/10/31 23:07:43 mlhuang Exp $
+# $Id: Auth.py,v 1.7 2006/11/08 22:53:30 mlhuang Exp $
 #
 
 import crypt
@@ -49,14 +49,14 @@ class SessionAuth(Auth):
         assert auth.has_key('session')
 
         # Get session record
-        sessions = Sessions(method.api, [auth['session']], expires = None).values()
+        sessions = Sessions(method.api, [auth['session']], expires = None)
         if not sessions:
             raise PLCAuthenticationFailure, "No such session"
         session = sessions[0]
 
         try:
             if session['node_id'] is not None:
-                nodes = Nodes(method.api, [session['node_id']]).values()
+                nodes = Nodes(method.api, [session['node_id']])
                 if not nodes:
                     raise PLCAuthenticationFailure, "No such node"
                 node = nodes[0]
@@ -67,7 +67,7 @@ class SessionAuth(Auth):
                 method.caller = node
 
             elif session['person_id'] is not None and session['expires'] > time.time():
-                persons = Persons(method.api, {'person_id': session['person_id'], 'enabled': True}).values()
+                persons = Persons(method.api, {'person_id': session['person_id'], 'enabled': True})
                 if not persons:
                     raise PLCAuthenticationFailure, "No such account"
                 person = persons[0]
@@ -129,7 +129,7 @@ class BootAuth(Auth):
         assert auth.has_key('node_id')
 
         try:
-            nodes = Nodes(method.api, [auth['node_id']]).values()
+            nodes = Nodes(method.api, [auth['node_id']])
             if not nodes:
                 raise PLCAuthenticationFailure, "No such node"
             node = nodes[0]
@@ -149,7 +149,7 @@ class BootAuth(Auth):
 
                 nodenetwork = None
                 if node['nodenetwork_ids']:
-                    nodenetworks = NodeNetworks(method.api, node['nodenetwork_ids']).values()
+                    nodenetworks = NodeNetworks(method.api, node['nodenetwork_ids'])
                     for nodenetwork in nodenetworks:
                         if nodenetwork['is_primary']:
                             break
@@ -220,7 +220,7 @@ class PasswordAuth(Auth):
         if len(persons) != 1:
             raise PLCAuthenticationFailure, "No such account"
 
-        person = persons.values()[0]
+        person = persons[0]
 
         if auth['Username'] == method.api.config.PLC_API_MAINTENANCE_USER:
             # "Capability" authentication, whatever the hell that was
index 613f03b..78853df 100644 (file)
@@ -4,7 +4,7 @@
 # Mark Huang <mlhuang@cs.princeton.edu>
 # Copyright (C) 2006 The Trustees of Princeton University
 #
-# $Id: ConfFiles.py,v 1.8 2006/11/08 22:55:29 mlhuang Exp $
+# $Id: ConfFiles.py,v 1.9 2006/11/09 03:07:42 mlhuang Exp $
 #
 
 from PLC.Faults import *
@@ -139,11 +139,11 @@ class ConfFiles(Table):
     Representation of the conf_files table in the database.
     """
 
-    def __init__(self, api, conf_file_filter = None):
-       Table.__init__(self, api, ConfFile)
+    def __init__(self, api, conf_file_filter = None, columns = None):
+       Table.__init__(self, api, ConfFile, columns)
 
         sql = "SELECT %s FROM view_conf_files WHERE True" % \
-              ", ".join(ConfFile.fields)
+              ", ".join(self.columns)
 
         if conf_file_filter is not None:
             if isinstance(conf_file_filter, (list, tuple, set)):
index 631c8d3..b8131c8 100644 (file)
@@ -4,7 +4,7 @@
 # Tony Mack <tmack@cs.princeton.edu>
 # Copyright (C) 2006 The Trustees of Princeton University
 #
-# $Id: Events.py,v 1.5 2006/11/08 22:55:55 mlhuang Exp $
+# $Id: Events.py,v 1.6 2006/11/09 03:07:42 mlhuang Exp $
 #
 
 from PLC.Faults import *
@@ -60,11 +60,11 @@ class Events(Table):
     Representation of row(s) from the events table in the database. 
     """
 
-    def __init__(self, api, event_filter):
-        Table.__init__(self, api, Event)
+    def __init__(self, api, event_filter = None, columns = None):
+        Table.__init__(self, api, Event, columns)
 
         sql = "SELECT %s FROM view_events WHERE True" % \
-              ", ".join(Event.fields)
+              ", ".join(self.columns)
 
         if event_filter is not None:
             if isinstance(event_filter, (list, tuple, set)):
index 7c34d91..2518c18 100644 (file)
@@ -42,12 +42,11 @@ class ForeignNode (Row) :
         
 
 class ForeignNodes (Table):
-
-    def __init__ (self, api, foreign_node_filter = None):
-        Table.__init__(self, api, ForeignNode)
+    def __init__ (self, api, foreign_node_filter = None, columns = None):
+        Table.__init__(self, api, ForeignNode, columns)
 
        sql = "SELECT %s FROM view_foreign_nodes WHERE deleted IS False" % \
-              ", ".join(ForeignNode.fields)
+              ", ".join(self.columns)
 
         if foreign_node_filter is not None:
             if isinstance(foreign_node_filter, (list, tuple, set)):
index c601195..841e6eb 100644 (file)
@@ -2,6 +2,7 @@ import re
 
 from PLC.Faults import *
 from PLC.Parameter import Parameter
+from PLC.Filter import Filter
 from PLC.Debug import profile
 from PLC.Table import Row, Table
 from PLC.KeyTypes import KeyType, KeyTypes
@@ -23,7 +24,8 @@ class Key(Row):
         }
 
     def validate_key_type(self, key_type):
-        if key_type not in KeyTypes(self.api):
+        key_types = [row['key_type'] for row in KeyTypes(self.api)]
+        if key_type not in key_types:
             raise PLCInvalidArgument, "Invalid key type"
        return key_type
 
@@ -96,13 +98,17 @@ class Keys(Table):
     database.
     """
 
-    def __init__(self, api, key_ids = None, is_blacklisted = False):
-        Table.__init__(self, api, Key)
+    def __init__(self, api, key_filter = None, columns = None):
+        Table.__init__(self, api, Key, columns)
        
        sql = "SELECT %s FROM keys WHERE is_blacklisted IS False" % \
-              ", ".join(Key.fields)
-
-       if key_ids:
-            sql += " AND key_id IN (%s)" %  ", ".join(map(str, key_ids))
+              ", ".join(self.columns)
+
+        if key_filter is not None:
+            if isinstance(key_filter, (list, tuple, set)):
+                key_filter = Filter(Key.fields, {'key_id': key_filter})
+            elif isinstance(key_filter, dict):
+                key_filter = Filter(Key.fields, key_filter)
+            sql += " AND (%s)" % key_filter.sql(api)
 
        self.selectall(sql)
index b3045b5..c03a07f 100644 (file)
@@ -30,12 +30,12 @@ class AddAddressTypeToAddress(Method):
     object_ids = []
 
     def call(self, auth, address_type_id_or_name, address_id):
-       address_types = AddressTypes(self.api, [address_type_id_or_name]).values()
+       address_types = AddressTypes(self.api, [address_type_id_or_name])
         if not address_types:
             raise PLCInvalidArgument, "No such address type"
         address_type = address_types[0]
 
-        addresses = Addresses(self.api, [address_id]).values()
+        addresses = Addresses(self.api, [address_id])
         if not addresses:
             raise PLCInvalidArgument, "No such address"
         address = addresses[0]
index 09de233..7ddb6b0 100644 (file)
@@ -33,13 +33,13 @@ class AddConfFileToNode(Method):
         conf_files = ConfFiles(self.api, [conf_file_id])
         if not conf_files:
             raise PLCInvalidArgument, "No such configuration file"
-        conf_file = conf_files.values()[0]
+        conf_file = conf_files[0]
 
         # Get node
        nodes = Nodes(self.api, [node_id_or_hostname])
        if not nodes:
                raise PLCInvalidArgument, "No such node"
-       node = nodes.values()[0]
+       node = nodes[0]
        
        # Link configuration file to node
         if node['node_id'] not in conf_file['node_ids']:
index 32b9f07..1d0a9ad 100644 (file)
@@ -34,13 +34,13 @@ class AddConfFileToNodeGroup(Method):
         conf_files = ConfFiles(self.api, [conf_file_id])
         if not conf_files:
             raise PLCInvalidArgument, "No such configuration file"
-        conf_file = conf_files.values()[0]
+        conf_file = conf_files[0]
 
         # Get node
        nodegroups = NodeGroups(self.api, [nodegroup_id_or_name])
        if not nodegroups:
             raise PLCInvalidArgument, "No such node group"
-       nodegroup = nodegroups.values()[0]
+       nodegroup = nodegroups[0]
        
        # Link configuration file to node
         if nodegroup['nodegroup_id'] not in conf_file['nodegroup_ids']:
index b702b53..5ccc735 100644 (file)
@@ -45,7 +45,7 @@ class AddNode(Method):
         if not sites:
             raise PLCInvalidArgument, "No such site"
 
-        site = sites.values()[0]
+        site = sites[0]
 
         # Authenticated function
         assert self.caller is not None
index 34498a6..a768662 100644 (file)
@@ -47,7 +47,7 @@ class AddNodeNetwork(Method):
         nodenetwork_fields = dict(filter(can_update, nodenetwork_fields.items()))
 
         # Check if node exists
-        nodes = Nodes(self.api, [node_id_or_hostname]).values()
+        nodes = Nodes(self.api, [node_id_or_hostname])
         if not nodes:
             raise PLCInvalidArgument, "No such node"
        node = nodes[0]
index b2c5678..9c40b36 100644 (file)
@@ -34,14 +34,14 @@ class AddNodeToNodeGroup(Method):
        nodes = Nodes(self.api, [node_id_or_hostname])
        if not nodes:
                raise PLCInvalidArgument, "No such node"
-       node = nodes.values()[0]
+       node = nodes[0]
 
        # Get nodegroup info
         nodegroups = NodeGroups(self.api, [nodegroup_id_or_name])
         if not nodegroups:
             raise PLCInvalidArgument, "No such nodegroup"
 
-        nodegroup = nodegroups.values()[0]
+        nodegroup = nodegroups[0]
        
        # add node to nodegroup
         if node['node_id'] not in nodegroup['node_ids']:
index 8debf2c..b7248b9 100644 (file)
@@ -36,18 +36,18 @@ class AddNodeToPCU(Method):
         if not nodes:
             raise PLCInvalidArgument, "No such node"
 
-        node = nodes.values()[0]
+        node = nodes[0]
 
         # Get PCU
         pcus = PCUs(self.api, [pcu_id])
         if not pcus:
             raise PLCInvalidArgument, "No such PCU"
 
-        pcu = pcus.values()[0]
+        pcu = pcus[0]
 
         if 'admin' not in self.caller['roles']:
             ok = False
-            sites = Sites(self.api, self.caller['site_ids']).values()
+            sites = Sites(self.api, self.caller['site_ids'])
             for site in sites:
                 if pcu['pcu_id'] in site['pcu_ids']:
                     ok = True
index fb77977..8866213 100644 (file)
@@ -42,7 +42,7 @@ class AddPCU(Method):
         pcu_fields = dict(filter(can_update, pcu_fields.items()))
 
         # Get associated site details
-        sites = Sites(self.api, [site_id_or_login_base]).values()
+        sites = Sites(self.api, [site_id_or_login_base])
         if not sites:
             raise PLCInvalidArgument, "No such site"
         site = sites[0]
index 74a6503..fb81132 100644 (file)
@@ -37,7 +37,7 @@ class AddPersonKey(Method):
         key_fields = dict(filter(can_update, key_fields.items()))
 
         # Get account details
-        persons = Persons(self.api, [person_id_or_email]).values()
+        persons = Persons(self.api, [person_id_or_email])
         if not persons:
             raise PLCInvalidArgument, "No such account"
         person = persons[0]
index 8d46624..fe24392 100644 (file)
@@ -35,14 +35,14 @@ class AddPersonToSite(Method):
         if not persons:
             raise PLCInvalidArgument, "No such account"
 
-        person = persons.values()[0]
+        person = persons[0]
 
         # Get site information
         sites = Sites(self.api, [site_id_or_login_base])
         if not sites:
             raise PLCInvalidArgument, "No such site"
 
-        site = sites.values()[0]
+        site = sites[0]
 
         if site['site_id'] not in person['site_ids']:
             site.add_person(person)
index a74389e..2ac6dd8 100644 (file)
@@ -34,14 +34,14 @@ class AddPersonToSlice(Method):
         if not persons:
             raise PLCInvalidArgument, "No such account"
 
-        person = persons.values()[0]
+        person = persons[0]
 
         # Get slice information
         slices = Slices(self.api, [slice_id_or_name])
         if not slices:
             raise PLCInvalidArgument, "No such slice"
 
-        slice = slices.values()[0]
+        slice = slices[0]
 
         # If we are not admin, make sure the caller is a PI
         # of the site associated with the slice
index dbc0215..ab3c364 100644 (file)
@@ -34,9 +34,9 @@ class AddRoleToPerson(Method):
     def call(self, auth, role_id_or_name, person_id_or_email):
         # Get all roles
         roles = {}
-        for role_id, role in Roles(self.api).iteritems():
-            roles[role_id] = role['name']
-            roles[role['name']] = role_id
+        for role in Roles(self.api):
+            roles[role['role_id']] = role['name']
+            roles[role['name']] = role['role_id']
 
         if role_id_or_name not in roles:
             raise PLCInvalidArgument, "Invalid role identifier or name"
@@ -51,7 +51,7 @@ class AddRoleToPerson(Method):
         if not persons:
             raise PLCInvalidArgument, "No such account"
 
-        person = persons.values()[0]
+        person = persons[0]
 
         # Authenticated function
         assert self.caller is not None
index 8a9c8a7..6f2c5dc 100644 (file)
@@ -40,7 +40,7 @@ class AddSiteAddress(Method):
         address_fields = dict(filter(can_update, address_fields.items()))
 
         # Get associated site details
-        sites = Sites(self.api, [site_id_or_login_base]).values()
+        sites = Sites(self.api, [site_id_or_login_base])
         if not sites:
             raise PLCInvalidArgument, "No such site"
         site = sites[0]
index c166e70..c946d7c 100644 (file)
@@ -57,7 +57,7 @@ class AddSlice(Method):
 
         # Get associated site details
         login_base = name.split("_")[0]
-        sites = Sites(self.api, [login_base]).values()
+        sites = Sites(self.api, [login_base])
         if not sites:
             raise PLCInvalidArgument, "Invalid slice prefix"
         site = sites[0]
index 6f808c4..c7b3c77 100644 (file)
@@ -42,12 +42,12 @@ class AddSliceAttribute(Method):
     object_ids = []
 
     def call(self, auth, slice_id_or_name, attribute_type_id_or_name, value, node_id_or_hostname = None):
-        slices = Slices(self.api, [slice_id_or_name]).values()
+        slices = Slices(self.api, [slice_id_or_name])
         if not slices:
             raise PLCInvalidArgument, "No such slice"
         slice = slices[0]
 
-        attribute_types = SliceAttributeTypes(self.api, [attribute_type_id_or_name]).values()
+        attribute_types = SliceAttributeTypes(self.api, [attribute_type_id_or_name])
         if not attribute_types:
             raise PLCInvalidArgument, "No such slice attribute type"
         attribute_type = attribute_types[0]
@@ -71,7 +71,7 @@ class AddSliceAttribute(Method):
 
         # Sliver attribute if node is specified
         if node_id_or_hostname is not None:
-            nodes = Nodes(self.api, [node_id_or_hostname]).values()
+            nodes = Nodes(self.api, [node_id_or_hostname])
             if not nodes:
                 raise PLCInvalidArgument, "No such node"
             node = nodes[0]
index 37ad4a3..9dcedbd 100644 (file)
@@ -40,7 +40,7 @@ class AddSliceToNodes(Method):
         if not slices:
             raise PLCInvalidArgument, "No such slice"
 
-        slice = slices.values()[0]
+        slice = slices[0]
 
         if 'admin' not in self.caller['roles']:
             if self.caller['person_id'] in slice['person_ids']:
@@ -53,13 +53,13 @@ class AddSliceToNodes(Method):
                 raise PLCPermissionDenied, "Specified slice not associated with any of your sites"
        
         # Get specified nodes, and them to the slice
-        nodes = Nodes(self.api, node_id_or_hostname_list).values()
+        nodes = Nodes(self.api, node_id_or_hostname_list)
        for node in nodes:
             if slice['slice_id'] not in node['slice_ids']:
                 slice.add_node(node, commit = False)
 
         # the same for foreign_nodes
-        foreign_nodes = ForeignNodes (self.api, node_id_or_hostname_list).values()
+        foreign_nodes = ForeignNodes (self.api, node_id_or_hostname_list)
         for foreign_node in foreign_nodes:
             if slice['slice_id'] not in foreign_node['slice_ids']:
                 slice.add_node (foreign_node, is_foreign_node=True, commit=False)
index 9cda950..9f038f9 100644 (file)
@@ -36,7 +36,7 @@ class AdmDeleteAllPersonKeys(Method):
         if not persons:
             raise PLCInvalidArgument, "No such account"
 
-        person = persons.values()[0]
+        person = persons[0]
 
         if 'admin' not in self.caller['roles']:
             if self.caller['person_id'] != person['person_id']:
@@ -47,7 +47,7 @@ class AdmDeleteAllPersonKeys(Method):
             return 1
 
         # Get associated key details
-        keys = Keys(self.api, key_ids).values()
+        keys = Keys(self.api, key_ids)
 
         for key in keys:
             key.delete()
index 0b9cd40..01d4055 100644 (file)
@@ -35,7 +35,7 @@ class AdmDeletePersonKeys(Method):
         if not persons:
             raise PLCInvalidArgument, "No such account"
 
-        person = persons.values()[0]
+        person = persons[0]
 
         if 'admin' not in self.caller['roles']:
             if self.caller['person_id'] != person['person_id']:
@@ -46,7 +46,7 @@ class AdmDeletePersonKeys(Method):
             return 1
 
         # Get associated key details
-        keys = Keys(self.api, key_ids).values()
+        keys = Keys(self.api, key_ids)
 
         for key in keys:
             key.delete()
index fa173c6..5f7c448 100644 (file)
@@ -24,11 +24,11 @@ class AdmDisassociatePowerControlUnitPort(DeleteNodeFromPCU):
     returns = Parameter(int, '1 if successful')
 
     def call(self, auth, pcu_id, port):
-        pcus = PCUs(self.api, [pcu_id]).values()
+        pcus = PCUs(self.api, [pcu_id])
         if not pcus:
             raise PLCInvalidArgument, "No such PCU"
 
-        pcu = pcus.values()[0]
+        pcu = pcus[0]
 
         ports = dict(zip(pcu['ports'], pcu['node_ids']))
         if port not in ports:
index 2af6a6f..ed968f9 100644 (file)
@@ -37,7 +37,7 @@ class AdmGenerateNodeConfFile(Method):
 
     def call(self, auth, node_id_or_hostname):
         # Get node information
-        nodes = Nodes(self.api, [node_id_or_hostname]).values()
+        nodes = Nodes(self.api, [node_id_or_hostname])
         if not nodes:
             raise PLCInvalidArgument, "No such node"
         node = nodes[0]
@@ -50,7 +50,7 @@ class AdmGenerateNodeConfFile(Method):
 
        # Get node networks for this node
         primary = None
-        nodenetworks = NodeNetworks(self.api, node['nodenetwork_ids']).values()
+        nodenetworks = NodeNetworks(self.api, node['nodenetwork_ids'])
         for nodenetwork in nodenetworks:
             if nodenetwork['is_primary']:
                 primary = nodenetwork
index 1504050..c00bdec 100644 (file)
@@ -26,7 +26,7 @@ class AdmGetAllNodeNetworks(GetNodeNetworks):
 
     def call(self, auth, node_id_or_hostname):
         # Get node information
-        nodes = Nodes(self.api, [node_id_or_hostname]).values()
+        nodes = Nodes(self.api, [node_id_or_hostname])
        if not nodes:
             raise PLCInvalidArgument, "No such node"
        node = nodes[0]
index 2daed59..51c392a 100644 (file)
@@ -30,7 +30,7 @@ class AdmGetNodeGroupNodes(Method):
             raise PLCInvalidArgument, "No such node group"
 
        # Get the info for the node group specified
-       nodegroup = nodegroups.values()[0]
+       nodegroup = nodegroups[0]
 
        # Return the list of node_ids
         return nodegroup['node_ids']
index 515d393..ab39d07 100644 (file)
@@ -31,7 +31,7 @@ class AdmGetPersonKeys(GetKeys):
         if not persons:
             raise PLCInvalidArgument, "No such account"
 
-        person = persons.values()[0]
+        person = persons[0]
 
         if 'admin' not in self.caller['roles']:
             if self.caller['person_id'] != person['person_id']:
index 2a862aa..024b93c 100644 (file)
@@ -39,7 +39,7 @@ class AdmGetPersonRoles(Method):
         if not persons:
             raise PLCInvalidArgument, "No such account"
 
-        person = persons.values()[0]
+        person = persons[0]
 
         # Authenticated function
         assert self.caller is not None
index 1807ef1..79324f8 100644 (file)
@@ -35,7 +35,7 @@ class AdmGetPersonSites(Method):
         if not persons:
             raise PLCInvalidArgument, "No such account"
 
-        person = persons.values()[0]
+        person = persons[0]
 
         # Authenticated function
         assert self.caller is not None
index 7319e68..af298ee 100644 (file)
@@ -28,7 +28,7 @@ class AdmGetPowerControlUnitNodes(Method):
                 'port_number': Parameter(int, "Port number")}]
 
     def call(self, auth, pcu_id):
-        pcus = PCUs(self.api, [pcu_id]).values()
+        pcus = PCUs(self.api, [pcu_id])
         if not pcus:
             raise PLCInvalidArgument, "No such PCU"
         pcu = pcus[0]
index ea09c09..b366c80 100644 (file)
@@ -32,7 +32,7 @@ class AdmGetSiteNodes(Method):
 
     def call(self, auth, site_id_or_name_list = None):
         # Get site information
-       sites = Sites(self.api, site_id_or_name_list).values()  
+       sites = Sites(self.api, site_id_or_name_list)   
        if not sites:
             raise PLCInvalidArgument, "No such site"
         
index 5d48285..d35ee88 100644 (file)
@@ -30,13 +30,13 @@ class AdmGetSitePIs(Method):
         assert self.caller is not None
 
         # Get site information
-       sites = Sites(self.api, [site_id_or_login_base]).values()
+       sites = Sites(self.api, [site_id_or_login_base])
        if not sites:
             raise PLCInvalidArgument, "No such site"
 
        site = sites[0]
 
-        persons = Persons(self.api, site['person_ids']).values()
+        persons = Persons(self.api, site['person_ids'])
 
         has_pi_role = lambda person: 'pi' in person['roles']
         pis = filter(has_pi_role, persons)
index ca6b47f..8122528 100644 (file)
@@ -31,7 +31,7 @@ class AdmGetSitePersons(Method):
         assert self.caller is not None
 
         # Get site information
-       sites = Sites(self.api, [site_id_or_login_base]).values()
+       sites = Sites(self.api, [site_id_or_login_base])
        if not sites:
             raise PLCInvalidArgument, "No such site"
 
index dd0b9a5..b95f298 100644 (file)
@@ -26,10 +26,10 @@ class AdmGetSitePowerControlUnits(Method):
         sites = Sites(self.api, [site_id_or_login_base])
         if not sites:
             raise PLCInvalidArgument, "No such site"
-        site = sites.values()[0]
+        site = sites[0]
 
         if 'admin' not in self.caller['roles']:
             if site['site_id'] not in self.caller['site_ids']:
                 raise PLCPermissionDenied, "Not allowed to view the PCUs at that site"
 
-        return PCUs(self.api, site['pcu_ids']).values()
+        return PCUs(self.api, site['pcu_ids'])
index b7eeaad..f531db5 100644 (file)
@@ -31,13 +31,13 @@ class AdmGetSiteTechContacts(Method):
         assert self.caller is not None
 
         # Get site information
-       sites = Sites(self.api, [site_id_or_login_base]).values()
+       sites = Sites(self.api, [site_id_or_login_base])
        if not sites:
             raise PLCInvalidArgument, "No such site"
 
        site = sites[0]
 
-        persons = Persons(self.api, site['person_ids']).values()
+        persons = Persons(self.api, site['person_ids'])
 
         has_tech_role = lambda person: 'tech' in person['roles']
         techs = filter(has_tech_role, persons)
index 119d0a1..b32ab03 100644 (file)
@@ -36,9 +36,9 @@ class AdmIsPersonInRole(Method):
 
         # Only allow PI roles to be checked
         roles = {}
-        for role_id, role in Roles(self.api).iteritems():
-            roles[role_id] = role['name']
-            roles[role['name']] = role_id
+        for role in Roles(self.api):
+            roles[role['role_id']] = role['name']
+            roles[role['name']] = role['role_id']
 
         if role_id_or_name not in roles:
             raise PLCInvalidArgument, "Invalid role identifier or name"
@@ -59,7 +59,7 @@ class AdmIsPersonInRole(Method):
         if not persons:
             return 0
 
-        person = persons.values()[0]
+        person = persons[0]
 
         if role_id in person['role_ids']:
             return 1
index 2fb0bcf..6cf5d99 100644 (file)
@@ -23,7 +23,7 @@ class AdmQueryConfFile(Method):
 
     def call(self, auth, search_vals):
         if 'node_id' in search_vals:
-            conf_files = ConfFiles(self.api).values()
+            conf_files = ConfFiles(self.api)
 
             conf_files = filter(lambda conf_file: \
                                 search_vals['node_id'] in conf_file['node_ids'],
index b2fe695..f41d04f 100644 (file)
@@ -30,7 +30,7 @@ class AdmQueryNode(Method):
     def call(self, auth, search_vals):
         # Get possible nodenetworks
         if 'node_hostname' in search_vals:
-            nodes = Nodes(self.api, [search_vals['node_hostname']]).values()
+            nodes = Nodes(self.api, [search_vals['node_hostname']])
             if not nodes:
                 return []
 
@@ -41,11 +41,11 @@ class AdmQueryNode(Method):
                 return [nodes[0]['node_id']]
 
             if nodes[0]['nodenetwork_ids']:
-                nodenetworks = NodeNetworks(self.api, nodes[0]['nodenetwork_ids']).values()
+                nodenetworks = NodeNetworks(self.api, nodes[0]['nodenetwork_ids'])
             else:
                 nodenetworks = []
         else:
-            nodenetworks = NodeNetworks(self.api).values()
+            nodenetworks = NodeNetworks(self.api)
 
         if 'nodenetwork_ip' in search_vals:
             if not valid_ip(search_vals['nodenetwork_ip']):
index 8d0c853..b41d0a5 100644 (file)
@@ -22,7 +22,7 @@ class AdmQueryPerson(Method):
 
     def call(self, auth, search_vals):
         if 'email' in search_vals:
-            persons = Persons(self.api, [search_vals['email']]).values()
+            persons = Persons(self.api, [search_vals['email']])
             if persons:
                 return [persons[0]['person_id']]
 
index 9392530..8fc2f42 100644 (file)
@@ -31,7 +31,7 @@ class AdmQueryPowerControlUnit(Method):
     def call(self, auth, search_vals):
         # Get all PCUs. This is a stupid function. The API should not
         # be used for DB mining.
-        pcus = PCUs(self.api).values()
+        pcus = PCUs(self.api)
 
         if 'pcu_hostname' in search_vals:
             pcus = filter(lambda pcu: \
@@ -53,7 +53,7 @@ class AdmQueryPowerControlUnit(Method):
         if 'node_hostname' in search_vals:
             pcus = filter(lambda pcu: \
                           search_vals['node_hostname'] in \
-                          [node['hostname'] for node in Nodes(self.api, pcu['node_ids']).values()],
+                          [node['hostname'] for node in Nodes(self.api, pcu['node_ids'])],
                           pcus)
 
         return [pcu['pcu_id'] for pcu in pcus]
index dbc2c3f..cad6b8c 100644 (file)
@@ -33,9 +33,9 @@ class AdmQuerySite(Method):
 
     def call(self, auth, search_vals):
         if 'site_loginbase' in search_vals:
-            sites = Sites(self.api, [search_vals['site_loginbase']]).values()
+            sites = Sites(self.api, [search_vals['site_loginbase']])
         else:
-            sites = Sites(self.api).values()
+            sites = Sites(self.api)
             
         if 'site_name' in search_vals:
             sites = filter(lambda site: \
@@ -60,12 +60,12 @@ class AdmQuerySite(Method):
                 site['ips'] = []
                 site['macs'] = []
                 if site['node_ids']:
-                    nodes = Nodes(self.api, site['node_ids']).values()
+                    nodes = Nodes(self.api, site['node_ids'])
                     for node in nodes:
                         site['hostnames'].append(node['hostname'])
                         if 'nodenetwork_ip' in search_vals or \
                            'nodenetwork_mac' in search_vals:
-                            nodenetworks = NodeNetworks(self.api, node['nodenetwork_ids']).values()
+                            nodenetworks = NodeNetworks(self.api, node['nodenetwork_ids'])
                             site['ips'] += [nodenetwork['ip'] for nodenetwork in nodenetworks]
                             site['macs'] += [nodenetwork['mac'] for nodenetwork in nodenetworks]
 
index 9b72492..17a0418 100644 (file)
@@ -30,7 +30,7 @@ class BlacklistKey(Method):
 
     def call(self, auth, key_id):
         # Get associated key details
-        keys = Keys(self.api, [key_id]).values()
+        keys = Keys(self.api, [key_id])
         if not keys:
             raise PLCInvalidArgument, "No such key"
         key = keys[0]
index e077576..0e8f710 100644 (file)
@@ -39,7 +39,7 @@ class BootGetNodeDetails(Method):
         details['session'] = session['session_id']
 
         if self.caller['nodenetwork_ids']:
-            details['networks'] = NodeNetworks(self.api, self.caller['nodenetwork_ids']).values()
+            details['networks'] = NodeNetworks(self.api, self.caller['nodenetwork_ids'])
             # XXX Boot Manager cannot unmarshal None
             for network in details['networks']:
                 for field in network:
index 79c86b6..b8c3396 100644 (file)
@@ -27,7 +27,7 @@ class BootNotifyOwners(Method):
     returns = Parameter(int, '1 if successful')
 
     def call(self, auth, message_id, include_pis, include_techs, include_support):
-        messages = Messages(self.api, [message_id], enabled = True).values()
+        messages = Messages(self.api, [message_id], enabled = True)
         if not messages:
             raise PLCInvalidArgument, "No such message template"
 
@@ -43,12 +43,12 @@ class BootNotifyOwners(Method):
             recipients[self.api.config.PLC_MAIL_SUPPORT_ADDRESS] = self.api.config.PLC_NAME + " Support"
 
         if include_pis or include_techs:
-            sites = Sites(self.api, [self.caller['site_id']]).values()
+            sites = Sites(self.api, [self.caller['site_id']])
             if not sites:
                 raise PLCAPIError, "No site associated with node"
             site = sites[0]
 
-            persons = Persons(self.api, site['person_ids']).values()
+            persons = Persons(self.api, site['person_ids'])
             for person in persons:
                 if include_pis and 'pi' in person['roles'] or \
                    include_techs and 'tech' in person['roles']:
index 42cf861..31dbb37 100644 (file)
@@ -46,7 +46,7 @@ class BootUpdateNode(Method):
             if primary_network['nodenetwork_id'] not in self.caller['nodenetwork_ids']:
                 raise PLCInvalidArgument, "Node network not associated with calling node"
 
-            nodenetworks = NodeNetworks(self.api, [primary_network['nodenetwork_id']]).values()
+            nodenetworks = NodeNetworks(self.api, [primary_network['nodenetwork_id']])
             if not nodenetworks:
                 raise PLCInvalidArgument, "No such node network"
             nodenetwork = nodenetworks[0]
index 3fecaec..99f1f51 100644 (file)
@@ -24,7 +24,7 @@ class DeleteAddress(Method):
 
     def call(self, auth, address_id):
         # Get associated address details
-        addresses = Addresses(self.api, [address_id]).values()
+        addresses = Addresses(self.api, [address_id])
         if not addresses:
             raise PLCInvalidArgument, "No such address"
         address = addresses[0]
index 445469e..662af3d 100644 (file)
@@ -22,7 +22,7 @@ class DeleteAddressType(Method):
     returns = Parameter(int, '1 if successful')
 
     def call(self, auth, address_type_id_or_name):
-        address_types = AddressTypes(self.api, [address_type_id_or_name]).values()
+        address_types = AddressTypes(self.api, [address_type_id_or_name])
         if not address_types:
             raise PLCInvalidArgument, "No such address type"
         address_type = address_types[0]
index 68a4840..3078737 100644 (file)
@@ -26,12 +26,12 @@ class DeleteAddressTypeFromAddress(Method):
     returns = Parameter(int, '1 if successful')
 
     def call(self, auth, address_type_id_or_name, address_id):
-        address_types = AddressTypes(self.api, [address_type_id_or_name]).values()
+        address_types = AddressTypes(self.api, [address_type_id_or_name])
         if not address_types:
             raise PLCInvalidArgument, "No such address type"
         address_type = address_types[0]
 
-        addresses = Addresses(self.api, [address_id]).values()
+        addresses = Addresses(self.api, [address_id])
         if not addresses:
             raise PLCInvalidArgument, "No such address"
         address = addresses[0]
index b516ef1..b7bce21 100644 (file)
@@ -27,7 +27,7 @@ class DeleteBootState(Method):
         boot_states = BootStates(self.api, [name])
         if not boot_states:
             raise PLCInvalidArgument, "No such boot state"
-        boot_state = boot_states.values()[0]
+        boot_state = boot_states[0]
 
         boot_state.delete()
 
index 0c7f0bf..e36d677 100644 (file)
@@ -21,7 +21,7 @@ class DeleteConfFile(Method):
     returns = Parameter(int, '1 if successful')
 
     def call(self, auth, conf_file_id):
-        conf_files = ConfFiles(self.api, [conf_file_id]).values()
+        conf_files = ConfFiles(self.api, [conf_file_id])
         if not conf_files:
             raise PLCInvalidArgument, "No such configuration file"
 
index e82c2f6..80985dd 100644 (file)
@@ -33,13 +33,13 @@ class DeleteConfFileFromNode(Method):
         conf_files = ConfFiles(self.api, [conf_file_id])
         if not conf_files:
             raise PLCInvalidArgument, "No such configuration file"
-        conf_file = conf_files.values()[0]
+        conf_file = conf_files[0]
 
         # Get node
        nodes = Nodes(self.api, [node_id_or_hostname])
        if not nodes:
                raise PLCInvalidArgument, "No such node"
-       node = nodes.values()[0]
+       node = nodes[0]
        
        # Link configuration file to node
         if node['node_id'] in conf_file['node_ids']:
index 22523db..300d311 100644 (file)
@@ -33,13 +33,13 @@ class DeleteConfFileFromNodeGroup(Method):
         conf_files = ConfFiles(self.api, [conf_file_id])
         if not conf_files:
             raise PLCInvalidArgument, "No such configuration file"
-        conf_file = conf_files.values()[0]
+        conf_file = conf_files[0]
 
         # Get nodegroup
        nodegroups = NodeGroups(self.api, [nodegroup_id_or_name])
        if not nodegroups:
                raise PLCInvalidArgument, "No such nodegroup"
-       nodegroup = nodegroups.values()[0]
+       nodegroup = nodegroups[0]
        
        # Link configuration file to nodegroup
         if nodegroup['nodegroup_id'] in conf_file['nodegroup_ids']:
index aef6084..ae39f31 100644 (file)
@@ -24,7 +24,7 @@ class DeleteKey(Method):
 
     def call(self, auth, key_id):
         # Get associated key details
-        keys = Keys(self.api, [key_id]).values()
+        keys = Keys(self.api, [key_id])
         if not keys:
             raise PLCInvalidArgument, "No such key"
         key = keys[0]
index 2a25c71..dc05655 100644 (file)
@@ -26,7 +26,7 @@ class DeleteKeyType(Method):
         key_types = KeyTypes(self.api, [name])
         if not key_types:
             raise PLCInvalidArgument, "No such key type"
-        key_type = key_types.values()[0]
+        key_type = key_types[0]
 
         key_type.delete()
 
index 40e5af2..82fbbaf 100644 (file)
@@ -22,7 +22,7 @@ class DeleteMessage(Method):
 
     def call(self, auth, message_id):
         # Get message information
-        messages = Messages(self.api, [message_id]).values()
+        messages = Messages(self.api, [message_id])
         if not messages:
             raise PLCInvalidArgument, "No such message"
         message = messages[0]
index 2238469..aa9e273 100644 (file)
@@ -27,7 +27,7 @@ class DeleteNetworkMethod(Method):
         network_methods = NetworkMethods(self.api, [name])
         if not network_methods:
             raise PLCInvalidArgument, "No such network method"
-        network_method = network_methods.values()[0]
+        network_method = network_methods[0]
 
         network_method.delete()
 
index f26232b..c84735f 100644 (file)
@@ -27,7 +27,7 @@ class DeleteNetworkType(Method):
         network_types = NetworkTypes(self.api, [name])
         if not network_types:
             raise PLCInvalidArgument, "No such network type"
-        network_type = network_types.values()[0]
+        network_type = network_types[0]
 
         network_type.delete()
 
index 038ed59..c4a2812 100644 (file)
@@ -30,7 +30,7 @@ class DeleteNode(Method):
         if not nodes:
             raise PLCInvalidArgument, "No such node"
 
-        node = nodes.values()[0]
+        node = nodes[0]
 
         # If we are not an admin, make sure that the caller is a
         # member of the site at which the node is located.
index 70c05ce..380c2cc 100644 (file)
@@ -30,14 +30,14 @@ class DeleteNodeFromNodeGroup(Method):
        if not nodes:
                raise PLCInvalidArgument, "No such node"
 
-       node = nodes.values()[0]
+       node = nodes[0]
 
        # Get nodegroup info
         nodegroups = NodeGroups(self.api, [nodegroup_id_or_name])
         if not nodegroups:
             raise PLCInvalidArgument, "No such nodegroup"
 
-        nodegroup = nodegroups.values()[0]
+        nodegroup = nodegroups[0]
 
        # Remove node from nodegroup
         if node['node_id'] in nodegroup['node_ids']:
index 70252f0..67a45f4 100644 (file)
@@ -31,18 +31,18 @@ class DeleteNodeFromPCU(Method):
         if not nodes:
             raise PLCInvalidArgument, "No such node"
 
-        node = nodes.values()[0]
+        node = nodes[0]
 
         # Get PCU
         pcus = PCUs(self.api, [pcu_id])
         if not pcus:
             raise PLCInvalidArgument, "No such PCU"
 
-        pcu = pcus.values()[0]
+        pcu = pcus[0]
 
         if 'admin' not in self.caller['roles']:
             ok = False
-            sites = Sites(self.api, self.caller['site_ids']).values()
+            sites = Sites(self.api, self.caller['site_ids'])
             for site in sites:
                 if pcu['pcu_id'] in site['pcu_ids']:
                     ok = True
index d6de9b7..59615f3 100644 (file)
@@ -29,7 +29,7 @@ class DeleteNodeGroup(Method):
         if not nodegroups:
             raise PLCInvalidArgument, "No such node group"
 
-        nodegroup = nodegroups.values()[0]
+        nodegroup = nodegroups[0]
 
         nodegroup.delete()
 
index 9deb4f1..05463df 100644 (file)
@@ -28,13 +28,13 @@ class DeleteNodeNetwork(Method):
 
     def call(self, auth, nodenetwork_id_or_ip):
         # Get node network information
-        nodenetworks = NodeNetworks(self.api, [nodenetwork_id_or_ip]).values()
+        nodenetworks = NodeNetworks(self.api, [nodenetwork_id_or_ip])
         if not nodenetworks:
             raise PLCInvalidArgument, "No such node network"
        nodenetwork = nodenetworks[0]
        
        # Get node information
-       nodes = Nodes(self.api, [nodenetwork['node_id']]).values()
+       nodes = Nodes(self.api, [nodenetwork['node_id']])
        if not nodes:
                raise PLCInvalidArgument, "No such node"
        node = nodes[0]
index 4b50a3f..01382b1 100644 (file)
@@ -24,7 +24,7 @@ class DeletePCU(Method):
 
     def call(self, auth, pcu_id):
         # Get associated PCU details
-        pcus = PCUs(self.api, [pcu_id]).values()
+        pcus = PCUs(self.api, [pcu_id])
         if not pcus:
             raise PLCInvalidArgument, "No such PCU"
         pcu = pcus[0]
index 2a6e8cc..e8a1030 100644 (file)
@@ -31,7 +31,7 @@ class DeletePerson(Method):
         if not persons:
             raise PLCInvalidArgument, "No such account"
 
-        person = persons.values()[0]
+        person = persons[0]
 
         # Authenticated function
         assert self.caller is not None
index 4479183..9004eae 100644 (file)
@@ -32,14 +32,14 @@ class DeletePersonFromSite(Method):
         if not persons:
             raise PLCInvalidArgument, "No such account"
 
-        person = persons.values()[0]
+        person = persons[0]
 
         # Get site information
         sites = Sites(self.api, [site_id_or_login_base])
         if not sites:
             raise PLCInvalidArgument, "No such site"
 
-        site = sites.values()[0]
+        site = sites[0]
 
         if site['site_id'] in person['site_ids']:
             site.remove_person(person)
index 8b5293c..f21db58 100644 (file)
@@ -31,14 +31,14 @@ class DeletePersonFromSlice(Method):
         if not persons:
             raise PLCInvalidArgument, "No such account"
 
-        person = persons.values()[0]
+        person = persons[0]
 
         # Get slice information
         slices = Slices(self.api, [slice_id_or_name])
         if not slices:
             raise PLCInvalidArgument, "No such slice"
 
-        slice = slices.values()[0]
+        slice = slices[0]
 
         # If we are not admin, make sure the caller is a pi
         # of the site associated with the slice
index bb4a471..53a3903 100644 (file)
@@ -29,7 +29,7 @@ class DeleteRole(Method):
         roles = Roles(self.api, [role_id_or_name])
         if not roles:
             raise PLCInvalidArgument, "No such role"
-        role = roles.values()[0]
+        role = roles[0]
 
         role.delete()
 
index 175c672..60ed91e 100644 (file)
@@ -30,9 +30,9 @@ class DeleteRoleFromPerson(Method):
     def call(self, auth, role_id_or_name, person_id_or_email):
         # Get all roles
         roles = {}
-        for role_id, role in Roles(self.api).iteritems():
-            roles[role_id] = role['name']
-            roles[role['name']] = role_id
+        for role in Roles(self.api):
+            roles[role['role_id']] = role['name']
+            roles[role['name']] = role['role_id']
 
         if role_id_or_name not in roles:
             raise PLCInvalidArgument, "Invalid role identifier or name"
@@ -47,7 +47,7 @@ class DeleteRoleFromPerson(Method):
         if not persons:
             raise PLCInvalidArgument, "No such account"
 
-        person = persons.values()[0]
+        person = persons[0]
 
         # Authenticated function
         assert self.caller is not None
index 545adfd..be5a8ae 100644 (file)
@@ -19,7 +19,7 @@ class DeleteSession(Method):
     def call(self, auth):
         assert auth.has_key('session')
 
-        sessions = Sessions(self.api, [auth['session']]).values()
+        sessions = Sessions(self.api, [auth['session']])
         if not sessions:
             raise PLCAPIError, "No such session"
         session = sessions[0]
index 28bfcee..d56d711 100644 (file)
@@ -33,7 +33,7 @@ class DeleteSite(Method):
         if not sites:
             raise PLCInvalidArgument, "No such site"
 
-        site = sites.values()[0]
+        site = sites[0]
         site.delete()
 
         return 1
index 6fdaa7a..1607d9c 100644 (file)
@@ -26,7 +26,7 @@ class DeleteSlice(Method):
     returns = Parameter(int, '1 if successful')
 
     def call(self, auth, slice_id_or_name):
-        slices = Slices(self.api, [slice_id_or_name]).values()
+        slices = Slices(self.api, [slice_id_or_name])
         if not slices:
             raise PLCInvalidArgument, "No such slice"
         slice = slices[0]
index 1afc9ce..7584f46 100644 (file)
@@ -29,12 +29,12 @@ class DeleteSliceAttribute(Method):
     returns = Parameter(int, '1 if successful')
 
     def call(self, auth, slice_attribute_id):
-        slice_attributes = SliceAttributes(self.api, [slice_attribute_id]).values()
+        slice_attributes = SliceAttributes(self.api, [slice_attribute_id])
         if not slice_attributes:
             raise PLCInvalidArgument, "No such slice attribute"
         slice_attribute = slice_attributes[0]
 
-        slices = Slices(self.api, [slice_attribute['slice_id']]).values()
+        slices = Slices(self.api, [slice_attribute['slice_id']])
         if not slices:
             raise PLCInvalidArgument, "No such slice"
         slice = slices[0]
index 66b64e8..db7816a 100644 (file)
@@ -22,7 +22,7 @@ class DeleteSliceAttributeType(Method):
     returns = Parameter(int, '1 if successful')
 
     def call(self, auth, attribute_type_id_or_name):
-        attribute_types = SliceAttributeTypes(self.api, [attribute_type_id_or_name]).values()
+        attribute_types = SliceAttributeTypes(self.api, [attribute_type_id_or_name])
         if not attribute_types:
             raise PLCInvalidArgument, "No such slice attribute type"
         attribute_type = attribute_types[0]
index 524a648..912f3b1 100644 (file)
@@ -31,10 +31,10 @@ class DeleteSliceFromNodes(Method):
         if not slices:
             raise PLCInvalidArgument, "No such slice"
 
-        slice = slices.values()[0]
+        slice = slices[0]
 
        # Get specified nodes
-        nodes = Nodes(self.api, node_id_or_hostname_list).values()
+        nodes = Nodes(self.api, node_id_or_hostname_list)
 
         if 'admin' not in self.caller['roles']:
             if self.caller['person_id'] in slice['person_ids']:
index 4d172e2..5c3c875 100644 (file)
@@ -26,7 +26,7 @@ class DeleteSliceInstantiation(Method):
         slice_instantiations = SliceInstantiations(self.api, [instantiation])
         if not slice_instantiations:
             raise PLCInvalidArgument, "No such slice instantiation state"
-        slice_instantiation = slice_instantiations.values()[0]
+        slice_instantiation = slice_instantiations[0]
 
         slice_instantiation.delete()
 
index 419027e..74d4f61 100644 (file)
@@ -8,9 +8,11 @@ from PLC.Auth import Auth
 class GetAddressTypes(Method):
     """
     Returns an array of structs containing details about address
-    types.  If address_type_filter is specified and is an array of
+    types. If address_type_filter is specified and is an array of
     address type identifiers, or a struct of address type attributes,
-    only address types matching the filter will be returned.
+    only address types matching the filter will be returned. If
+    return_fields is specified, only the specified details will be
+    returned.
     """
 
     roles = ['admin', 'pi', 'user', 'tech']
@@ -19,10 +21,11 @@ class GetAddressTypes(Method):
         Auth(),
         Mixed([Mixed(AddressType.fields['address_type_id'],
                      AddressType.fields['name'])],
-              Filter(AddressType.fields))
+              Filter(AddressType.fields)),
+        Parameter([str], "List of fields to return", nullok = True)
         ]
 
     returns = [AddressType.fields]
 
-    def call(self, auth, address_type_filter = None):
-        return AddressTypes(self.api, address_type_filter).values()
+    def call(self, auth, address_type_filter = None, return_fields = None):
+        return AddressTypes(self.api, address_type_filter, return_fields)
index 567cd98..3aa9eeb 100644 (file)
@@ -10,7 +10,8 @@ class GetAddresses(Method):
     Returns an array of structs containing details about addresses. If
     address_filter is specified and is an array of address
     identifiers, or a struct of address attributes, only addresses
-    matching the filter will be returned.
+    matching the filter will be returned. If return_fields is
+    specified, only the specified details will be returned.
     """
 
     roles = ['admin', 'pi', 'user', 'tech']
@@ -18,10 +19,11 @@ class GetAddresses(Method):
     accepts = [
         Auth(),
         Mixed([Address.fields['address_id']],
-              Filter(Address.fields))
+              Filter(Address.fields)),
+        Parameter([str], "List of fields to return", nullok = True)
         ]
 
     returns = [Address.fields]
 
-    def call(self, auth, address_filter = None):
-        return Addresses(self.api, address_filter).values()
+    def call(self, auth, address_filter = None, return_fields = None):
+        return Addresses(self.api, address_filter, return_fields)
index 25c6c7d..1afa53b 100644 (file)
@@ -18,4 +18,4 @@ class GetBootStates(Method):
     returns = [BootState.fields['boot_state']]
 
     def call(self, auth):
-        return [boot_state['boot_state'] for boot_state in BootStates(self.api).values()]
+        return [boot_state['boot_state'] for boot_state in BootStates(self.api)]
index d12365e..6a10f90 100644 (file)
@@ -11,7 +11,8 @@ class GetConfFiles(Method):
     files. If conf_file_filter is specified and is an array of
     configuration file identifiers, or a struct of configuration file
     attributes, only configuration files matching the filter will be
-    returned.
+    returned. If return_fields is specified, only the specified
+    details will be returned.
     """
 
     roles = ['admin']
@@ -19,10 +20,11 @@ class GetConfFiles(Method):
     accepts = [
         Auth(),
         Mixed([ConfFile.fields['conf_file_id']],
-              Filter(ConfFile.fields))
+              Filter(ConfFile.fields)),
+        Parameter([str], "List of fields to return", nullok = True)
         ]
 
     returns = [ConfFile.fields]
 
-    def call(self, auth, conf_file_filter = None):
-        return ConfFiles(self.api, conf_file_filter).values()
+    def call(self, auth, conf_file_filter = None, return_fields = None):
+        return ConfFiles(self.api, conf_file_filter, return_fields)
index 30f246e..4fbb451 100644 (file)
@@ -10,7 +10,8 @@ class GetEvents(Method):
     Returns an array of structs containing details about events and
     faults. If event_filter is specified and is an array of event
     identifiers, or a struct of event attributes, only events matching
-    the filter will be returned.
+    the filter will be returned. If return_fields is specified, only the
+    specified details will be returned.
     """
 
     roles = ['admin']
@@ -18,10 +19,11 @@ class GetEvents(Method):
     accepts = [
         Auth(),
         Mixed([Event.fields['event_id']],
-              Filter(Event.fields))
+              Filter(Event.fields)),
+        Parameter([str], "List of fields to return", nullok = True)
         ]
 
     returns = [Event.fields]
 
-    def call(self, auth, event_filter = None):
-        return Events(self.api, event_filter).values()
+    def call(self, auth, event_filter = None, return_fields = None):
+        return Events(self.api, event_filter, return_fields)
index 9676da4..f8f2fb1 100644 (file)
@@ -16,7 +16,8 @@ class GetForeignNodes(Method):
     nodes. If foreign_node_filter is specified and is an array of
     foreign node identifiers or hostnames, or a struct of foreign node
     attributes, only foreign nodes matching the filter will be
-    returned.
+    returned. If return_fields is specified, only the specified
+    details will be returned.
     """
 
     roles = ['admin']
@@ -25,10 +26,11 @@ class GetForeignNodes(Method):
         Auth(),
         Mixed([Mixed(ForeignNode.fields['node_id'],
                      ForeignNode.fields['hostname'])],
-              Filter(ForeignNode.fields))
+              Filter(ForeignNode.fields)),
+        Parameter([str], "List of fields to return", nullok = True)
         ]
     
     returns = [ForeignNode.fields]
 
-    def call(self, auth, foreign_node_filter = None):
-       return ForeignNodes(self.api, foreign_node_filter).values()
+    def call(self, auth, foreign_node_filter = None, return_fields = None):
+       return ForeignNodes(self.api, foreign_node_filter, return_fields)
index f005b99..f8a554b 100644 (file)
@@ -18,4 +18,4 @@ class GetKeyTypes(Method):
     returns = [KeyType.fields['key_type']]
 
     def call(self, auth):
-        return [key_type['key_type'] for key_type in KeyTypes(self.api).values()]
+        return [key_type['key_type'] for key_type in KeyTypes(self.api)]
index 9f8f7f4..fcbd2b1 100644 (file)
@@ -1,13 +1,17 @@
 from PLC.Faults import *
 from PLC.Method import Method
 from PLC.Parameter import Parameter, Mixed
+from PLC.Filter import Filter
 from PLC.Keys import Key, Keys
 from PLC.Auth import Auth
 
 class GetKeys(Method):
     """
     Returns an array of structs containing details about keys. If
-    key_ids is specified, only the specified keys will be queried.
+    key_filter is specified and is an array of key identifiers, or a
+    struct of key attributes, only keys matching the filter will be
+    returned. If return_fields is specified, only the specified
+    details will be returned.
 
     Admin may query all keys. Non-admins may only query their own
     keys.
@@ -17,16 +21,18 @@ class GetKeys(Method):
 
     accepts = [
         Auth(),
-        [Key.fields['key_id']]
+        Mixed([Mixed(Key.fields['key_id'])],
+              Filter(Key.fields)),
+        Parameter([str], "List of fields to return", nullok = True)        
         ]
 
     returns = [Key.fields]
 
-    def call(self, auth, key_ids = None):
+    def call(self, auth, key_filter = None, return_fields = None):
+       keys = Keys(self.api, key_filter, return_fields)
+
        # If we are not admin, make sure to only return our own keys       
         if 'admin' not in self.caller['roles']:
-            key_ids = set(key_ids).intersection(self.caller['key_ids'])
-            if not key_ids:
-                return []
+            keys = filter(lambda key: key['key_id'] in self.caller['key_ids'], keys)
 
-       return Keys(self.api, key_ids).values()
+        return keys
index 12bd315..6605324 100644 (file)
@@ -25,4 +25,4 @@ class GetMessages(Method):
     object_ids = []
 
     def call(self, auth, message_ids = None):
-        return Messages(self.api, message_ids).values()
+        return Messages(self.api, message_ids)
index c678447..e857dd5 100644 (file)
@@ -18,4 +18,4 @@ class GetNetworkMethods(Method):
     returns = [NetworkMethod.fields['method']]
 
     def call(self, auth):
-        return [network_method['method'] for network_method in NetworkMethods(self.api).values()]
+        return [network_method['method'] for network_method in NetworkMethods(self.api)]
index ed6ec88..7187d21 100644 (file)
@@ -18,4 +18,4 @@ class GetNetworkTypes(Method):
     returns = [NetworkType.fields['type']]
 
     def call(self, auth):
-        return [network_type['type'] for network_type in NetworkTypes(self.api).values()]
+        return [network_type['type'] for network_type in NetworkTypes(self.api)]
index c41b8b9..478eb99 100644 (file)
@@ -10,7 +10,8 @@ class GetNodeGroups(Method):
     Returns an array of structs containing details about node groups.
     If nodegroup_filter is specified and is an array of node group
     identifiers or names, or a struct of node group attributes, only
-    node groups matching the filter will be returned.
+    node groups matching the filter will be returned. If return_fields
+    is specified, only the specified details will be returned.
     """
 
     roles = ['admin', 'pi', 'user', 'tech']
@@ -19,10 +20,11 @@ class GetNodeGroups(Method):
         Auth(),
         Mixed([Mixed(NodeGroup.fields['nodegroup_id'],
                      NodeGroup.fields['name'])],
-              Filter(NodeGroup.fields))
+              Filter(NodeGroup.fields)),
+        Parameter([str], "List of fields to return", nullok = True)
         ]
 
     returns = [NodeGroup.fields]
   
-    def call(self, auth, nodegroup_filter = None):
-       return NodeGroups(self.api, nodegroup_filter).values()
+    def call(self, auth, nodegroup_filter = None, return_fields = None):
+       return NodeGroups(self.api, nodegroup_filter, return_fields)
index e2a8c85..4562c00 100644 (file)
@@ -11,7 +11,8 @@ class GetNodeNetworks(Method):
     interfacess. If nodenetworks_filter is specified and is an array
     of node network identifiers, or a struct of node network
     attributes, only node network interfaces matching the filter will
-    be returned.
+    be returned. If return_fields is specified, only the
+    specified details will be returned.
     """
 
     roles = ['admin', 'pi', 'user', 'tech']
@@ -19,10 +20,11 @@ class GetNodeNetworks(Method):
     accepts = [
         Auth(),
         Mixed([NodeNetwork.fields['nodenetwork_id']],
-              Filter(NodeNetwork.fields))
+              Filter(NodeNetwork.fields)),
+        Parameter([str], "List of fields to return", nullok = True)
         ]
 
     returns = [NodeNetwork.fields]
 
-    def call(self, auth, nodenetwork_filter = None):
-        return NodeNetworks(self.api, nodenetwork_filter).values()
+    def call(self, auth, nodenetwork_filter = None, return_fields = None):
+        return NodeNetworks(self.api, nodenetwork_filter, return_fields)
index a2c2566..22b8e01 100644 (file)
@@ -10,7 +10,8 @@ class GetNodes(Method):
     Returns an array of structs containing details about nodes. If
     node_filter is specified and is an array of node identifiers or
     hostnames, or a struct of node attributes, only nodes matching the
-    filter will be returned.
+    filter will be returned. If return_fields is specified, only the
+    specified details will be returned.
 
     Some fields may only be viewed by admins.
     """
@@ -21,14 +22,15 @@ class GetNodes(Method):
         Auth(),
         Mixed([Mixed(Node.fields['node_id'],
                      Node.fields['hostname'])],
-              Filter(Node.fields))
+              Filter(Node.fields)),
+        Parameter([str], "List of fields to return", nullok = True)
         ]
 
     returns = [Node.fields]
 
-    def call(self, auth, node_filter = None):
+    def call(self, auth, node_filter = None, return_fields = None):
         # Get node information
-        nodes = Nodes(self.api, node_filter).values()
+        nodes = Nodes(self.api, node_filter, return_fields)
 
         # Remove admin only fields
         if 'admin' not in self.caller['roles']:
index dbf371e..13bd7dc 100644 (file)
@@ -10,7 +10,8 @@ class GetPCUs(Method):
     Returns an array of structs containing details about power control
     units (PCUs). If pcu_filter is specified and is an array of PCU
     identifiers, or a struct of PCU attributes, only PCUs matching the
-    filter will be returned.
+    filter will be returned. If return_fields is specified, only the
+    specified details will be returned.
 
     Admin may query all PCUs. Non-admins may only query the PCUs at
     their sites.
@@ -21,18 +22,19 @@ class GetPCUs(Method):
     accepts = [
         Auth(),
         Mixed([PCU.fields['pcu_id']],
-              Filter(PCU.fields))
+              Filter(PCU.fields)),
+        Parameter([str], "List of fields to return", nullok = True)
         ]
 
     returns = [PCU.fields]
 
-    def call(self, auth, pcu_filter = None):
+    def call(self, auth, pcu_filter = None, return_fields = None):
        # If we are not admin, make sure to only return our own PCUs
         if 'admin' not in self.caller['roles']:
             # Get list of PCUs that we are able to view
             valid_pcu_ids = []
             if self.caller['site_ids']:
-                sites = Sites(self.api, self.caller['site_ids']).values()
+                sites = Sites(self.api, self.caller['site_ids'])
                 for site in sites:
                     valid_pcu_ids += site['pcu_ids']
 
@@ -42,7 +44,7 @@ class GetPCUs(Method):
             if pcu_filter is None:
                 pcu_filter = valid_pcu_ids
 
-        pcus = PCUs(self.api, pcu_filter).values()
+        pcus = PCUs(self.api, pcu_filter, return_fields)
 
         # Filter out PCUs that are not viewable
         if 'admin' not in self.caller['roles']:
index e4fd459..b7509b0 100644 (file)
@@ -15,7 +15,8 @@ class GetPeers (Method):
     Returns an array of structs containing details about peers. If
     person_filter is specified and is an array of peer identifiers or
     peer names, or a struct of peer attributes, only peers matching
-    the filter will be returned.
+    the filter will be returned. If return_fields is specified, only the
+    specified details will be returned.
     """
 
     roles = ['admin']
@@ -24,10 +25,11 @@ class GetPeers (Method):
         Auth(),
         Mixed([Mixed(Peer.fields['peer_id'],
                      Peer.fields['peername'])],
-              Filter(Peer.fields))
+              Filter(Peer.fields)),
+        Parameter([str], "List of fields to return", nullok = True)        
         ]
 
     returns = [Peer.fields]
 
-    def call (self, auth, peer_filter = None):
-       return Peers(self.api, peer_filter).values()
+    def call (self, auth, peer_filter = None, return_fields = None):
+       return Peers(self.api, peer_filter, return_fields)
index d0f4b2d..e29d109 100644 (file)
@@ -10,7 +10,8 @@ class GetPersons(Method):
     Returns an array of structs containing details about users. If
     person_filter is specified and is an array of user identifiers or
     usernames, or a struct of user attributes, only users matching the
-    filter will be returned.
+    filter will be returned. If return_fields is specified, only the
+    specified details will be returned.
 
     Users and techs may only retrieve details about themselves. PIs
     may retrieve details about themselves and others at their
@@ -23,7 +24,8 @@ class GetPersons(Method):
         Auth(),
         Mixed([Mixed(Person.fields['person_id'],
                      Person.fields['email'])],
-              Filter(Person.fields))
+              Filter(Person.fields)),
+        Parameter([str], "List of fields to return", nullok = True)
         ]
 
     # Filter out password field
@@ -31,13 +33,13 @@ class GetPersons(Method):
     return_fields = dict(filter(can_return, Person.fields.items()))
     returns = [return_fields]
 
-    def call(self, auth, person_filter = None):
+    def call(self, auth, person_filter = None, return_fields = None):
        # If we are not admin, make sure to only return viewable accounts
         if 'admin' not in self.caller['roles']:
             # Get accounts that we are able to view
             valid_person_ids = [self.caller['person_id']]
             if 'pi' in self.caller['roles'] and self.caller['site_ids']:
-                sites = Sites(self.api, self.caller['site_ids']).values()
+                sites = Sites(self.api, self.caller['site_ids'])
                 for site in sites:
                     valid_person_ids += site['person_ids']
 
@@ -47,7 +49,12 @@ class GetPersons(Method):
             if person_filter is None:
                 person_filter = valid_person_ids
 
-        persons = Persons(self.api, person_filter).values()
+        # Filter out password field
+        if return_fields:
+            while 'password' in return_fields:
+                return_fields.remove('password')
+
+        persons = Persons(self.api, person_filter, return_fields)
 
         # Filter out accounts that are not viewable
         if 'admin' not in self.caller['roles']:
index 9f7e7b1..a53d775 100644 (file)
@@ -18,4 +18,4 @@ class GetRoles(Method):
     returns = [Role.fields]
 
     def call(self, auth):
-       return Roles(self.api).values()
+       return Roles(self.api)
index 885e280..11c2708 100644 (file)
@@ -6,9 +6,11 @@ from PLC.Sites import Site, Sites
 
 class GetSites(Method):
     """
-    Return an array of structs containing details about all sites. If
-    site_id_list is specified, only the specified sites will be
-    queried.
+    Returns an array of structs containing details about sites. If
+    site_filter is specified and is an array of site identifiers or
+    hostnames, or a struct of site attributes, only sites matching the
+    filter will be returned. If return_fields is specified, only the
+    specified details will be returned.
     """
 
     roles = ['admin', 'pi', 'user', 'tech']
@@ -17,7 +19,8 @@ class GetSites(Method):
         Auth(),
         Mixed([Mixed(Site.fields['site_id'],
                      Site.fields['login_base'])],
-              Filter(Site.fields))
+              Filter(Site.fields)),
+        Parameter([str], "List of fields to return", nullok = True)        
         ]
 
     returns = [Site.fields]
@@ -26,5 +29,5 @@ class GetSites(Method):
     object_type = 'Site'
     object_ids = []
        
-    def call(self, auth, site_filter = None):
-        return Sites(self.api, site_filter).values()
+    def call(self, auth, site_filter = None, return_fields = None):
+        return Sites(self.api, site_filter, return_fields)
index 0495523..5511e58 100644 (file)
@@ -6,9 +6,12 @@ from PLC.SliceAttributeTypes import SliceAttributeType, SliceAttributeTypes
 
 class GetSliceAttributeTypes(Method):
     """
-    Return an array of structs containing details about all possible
-    slice and node attributes. If attribute_id_or_name_list is
-    specified, only the specified attributes will be queried.
+    Returns an array of structs containing details about slice
+    attribute types. If attribute_type_filter is specified and
+    is an array of slice attribute type identifiers, or a
+    struct of slice attribute type attributes, only slice attribute
+    types matching the filter will be returned. If return_fields is
+    specified, only the specified details will be returned.
     """
 
     roles = ['admin', 'pi', 'user', 'tech']
@@ -17,10 +20,11 @@ class GetSliceAttributeTypes(Method):
         Auth(),
         Mixed([Mixed(SliceAttributeType.fields['attribute_type_id'],
                      SliceAttributeType.fields['name'])],
-              Filter(SliceAttributeType.fields))
+              Filter(SliceAttributeType.fields)),
+        Parameter([str], "List of fields to return", nullok = True)
         ]
 
     returns = [SliceAttributeType.fields]
 
-    def call(self, auth, attribute_type_filter = None):
-        return SliceAttributeTypes(self.api, attribute_type_filter).values()
+    def call(self, auth, attribute_type_filter = None, return_fields = None):
+        return SliceAttributeTypes(self.api, attribute_type_filter, return_fields)
index af5deec..5a6a447 100644 (file)
@@ -9,10 +9,13 @@ from PLC.Auth import Auth
 
 class GetSliceAttributes(Method):
     """
-    Get an array of structs containing the values of slice and sliver
-    attributes. An attribute is a sliver attribute if the node_id
-    field is set. If slice_attribute_id_list is specified, only the
-    specified attributes will be queried, if set.
+    Returns an array of structs containing details about slice and
+    sliver attributes. An attribute is a sliver attribute if the
+    node_id field is set. If slice_attribute_filter is specified and
+    is an array of slice attribute identifiers, or a struct of slice
+    attribute attributes, only slice attributes matching the filter
+    will be returned. If return_fields is specified, only the
+    specified details will be returned.
 
     Users may only query attributes of slices or slivers of which they
     are members. PIs may only query attributes of slices or slivers at
@@ -25,19 +28,20 @@ class GetSliceAttributes(Method):
     accepts = [
         Auth(),
         Mixed([SliceAttribute.fields['slice_attribute_id']],
-              Filter(SliceAttribute.fields))
+              Filter(SliceAttribute.fields)),
+        Parameter([str], "List of fields to return", nullok = True)
         ]
 
     returns = [SliceAttribute.fields]
 
-    def call(self, auth, slice_attribute_filter = None):
+    def call(self, auth, slice_attribute_filter = None, return_fields = None):
        # If we are not admin, make sure to only return our own slice
        # and sliver attributes.
         if 'admin' not in self.caller['roles']:
             # Get slices that we are able to view
             valid_slice_ids = self.caller['slice_ids']
             if 'pi' in self.caller['roles'] and self.caller['site_ids']:
-                sites = Sites(self.api, self.caller['site_ids']).values()
+                sites = Sites(self.api, self.caller['site_ids'])
                 for site in sites:
                     valid_slice_ids += site['slice_ids']
 
@@ -46,7 +50,7 @@ class GetSliceAttributes(Method):
 
             # Get slice attributes that we are able to view
             valid_slice_attribute_ids = []
-            slices = Slices(self.api, valid_slice_ids).values()
+            slices = Slices(self.api, valid_slice_ids)
             for slice in slices:
                 valid_slice_attribute_ids += slice['slice_attribute_ids']
 
@@ -56,7 +60,7 @@ class GetSliceAttributes(Method):
             if slice_attribute_filter is None:
                 slice_attribute_filter = valid_slice_attribute_ids
 
-        slice_attributes = SliceAttributes(self.api, slice_attribute_filter).values()
+        slice_attributes = SliceAttributes(self.api, slice_attribute_filter, return_fields)
 
         # Filter out slice attributes that are not viewable
         if 'admin' not in self.caller['roles']:
index 31f2048..25a856d 100644 (file)
@@ -18,4 +18,4 @@ class GetSliceInstantiations(Method):
     returns = [SliceInstantiation.fields['instantiation']]
 
     def call(self, auth):
-        return [slice_instantiation['instantiation'] for slice_instantiation in SliceInstantiations(self.api).values()]
+        return [slice_instantiation['instantiation'] for slice_instantiation in SliceInstantiations(self.api)]
index 478ff95..ac3c69e 100644 (file)
@@ -9,13 +9,13 @@ class GetSlices(Method):
     Returns an array of structs containing details about slices. If
     slice_filter is specified and is an array of slice identifiers or
     slice names, or a struct of slice attributes, only slices matching
-    the filter will be returned.
+    the filter will be returned. If return_fields is specified, only the
+    specified details will be returned.
 
     Users may only query slices of which they are members. PIs may
     query any of the slices at their sites. Admins may query any
     slice. If a slice that cannot be queried is specified in
-    slice_id_or_name_list, details about that slice will not be
-    returned.
+    slice_filter, details about that slice will not be returned.
     """
 
     roles = ['admin', 'pi', 'user']
@@ -24,19 +24,20 @@ class GetSlices(Method):
         Auth(),
         Mixed([Mixed(Slice.fields['slice_id'],
                      Slice.fields['name'])],
-              Filter(Slice.fields))
+              Filter(Slice.fields)),
+        Parameter([str], "List of fields to return", nullok = True)
         ]
 
     returns = [Slice.fields]
 
-    def call(self, auth, slice_filter = None):
+    def call(self, auth, slice_filter = None, return_fields = None):
        # If we are not admin, make sure to return only viewable
        # slices.
         if 'admin' not in self.caller['roles']:
             # Get slices that we are able to view
             valid_slice_ids = self.caller['slice_ids']
             if 'pi' in self.caller['roles'] and self.caller['site_ids']:
-                sites = Sites(self.api, self.caller['site_ids']).values()
+                sites = Sites(self.api, self.caller['site_ids'])
                 for site in sites:
                     valid_slice_ids += site['slice_ids']
 
@@ -46,11 +47,10 @@ class GetSlices(Method):
             if slice_filter is None:
                 slice_filter = valid_slice_ids
 
-        slices = Slices(self.api, slice_filter).values()
+        slices = Slices(self.api, slice_filter, return_fields)
 
         # Filter out slices that are not viewable
         if 'admin' not in self.caller['roles']:
-            can_view = lambda slice: slice['slice_id'] in valid_slice_ids
-            slices = filter(can_view, slices)
+            slices = filter(lambda slice: slice['slice_id'] in valid_slice_ids, slices)
 
         return slices
index 04982d4..181db4d 100644 (file)
@@ -3,6 +3,7 @@ import time
 from PLC.Faults import *
 from PLC.Method import Method
 from PLC.Parameter import Parameter, Mixed
+from PLC.Filter import Filter
 from PLC.Auth import Auth
 from PLC.Nodes import Node, Nodes
 from PLC.NodeNetworks import NodeNetwork, NodeNetworks
@@ -13,13 +14,19 @@ from PLC.Persons import Person, Persons
 from PLC.Keys import Key, Keys
 from PLC.SliceAttributes import SliceAttribute, SliceAttributes
 
+def hashref(rows, key_field):
+    d = {}
+    for row in rows:
+        d[row[key_field]] = row
+    return d
+
 class GetSlivers(Method):
     """
     Returns an array of structs representing nodes and their slivers
-    (slices bound to nodes). If node_hostnames is specified, only
-    information about the specified nodes will be returned. If not
-    specified and called by a node, only information about the caller
-    will be returned.
+    (slices bound to nodes). If node_filter is specified, only
+    information about the specified nodes will be returned. If
+    node_filter is not specified and called by a node, only
+    information about the caller will be returned.
 
     All of the information returned by this call can be gathered from
     other calls, e.g. GetNodes, GetNodeNetworks, GetSlices, etc. This
@@ -31,15 +38,15 @@ class GetSlivers(Method):
 
     accepts = [
         Auth(),
-        [Mixed(Node.fields['node_id'],
-               Node.fields['hostname'])]
+        Mixed([Mixed(Node.fields['node_id'],
+                     Node.fields['hostname'])],
+              Filter(Node.fields)),
         ]
 
     returns = [{
         'timestamp': Parameter(int, "Timestamp of this call, in seconds since UNIX epoch"),
         'node_id': Node.fields['node_id'],
         'hostname': Node.fields['hostname'],
-        'boot_state': Node.fields['boot_state'],
         'networks': [NodeNetwork.fields],
         'groups': [NodeGroup.fields['name']],
         'conf_files': [ConfFile.fields],
@@ -59,13 +66,13 @@ class GetSlivers(Method):
         }]
     }]
 
-    def call(self, auth, node_id_or_hostname_list = None):
+    def call(self, auth, node_filter = None):
         timestamp = int(time.time())
 
-        if node_id_or_hostname_list is None and isinstance(self.caller, Node):
+        if node_filter is None and isinstance(self.caller, Node):
             all_nodes = {self.caller['node_id']: self.caller}
         else:
-            all_nodes = Nodes(self.api, node_id_or_hostname_list)
+            all_nodes = hashref(Nodes(self.api, node_filter), 'node_id')
             # XXX Add foreign nodes
 
         nodenetwork_ids = set()
@@ -77,23 +84,17 @@ class GetSlivers(Method):
             slice_ids.update(node['slice_ids'])
 
         # Get nodenetwork information
-        if nodenetwork_ids:
-            all_nodenetworks = NodeNetworks(self.api, nodenetwork_ids)
-        else:
-            all_nodenetworks = {}
+        all_nodenetworks = hashref(NodeNetworks(self.api, nodenetwork_ids), 'nodenetwork_id')
 
         # Get node group information
-        if nodegroup_ids:
-            all_nodegroups = NodeGroups(self.api, nodegroup_ids)
-        else:
-            all_nodegroups = {}
+        all_nodegroups = hashref(NodeGroups(self.api, nodegroup_ids), 'nodegroup_id')
 
-        # Get configuration files
-        all_conf_files = ConfFiles(self.api, {'enabled': True})
+        # Get (enabled) configuration files
+        all_conf_files = hashref(ConfFiles(self.api, {'enabled': True}), 'conf_file_id')
 
         if slice_ids:
             # Get slices
-            all_slices = Slices(self.api, slice_ids)
+            all_slices = hashref(Slices(self.api, slice_ids), 'slice_id')
 
             person_ids = set()
             slice_attribute_ids = set()
@@ -102,36 +103,44 @@ class GetSlivers(Method):
                 slice_attribute_ids.update(slice['slice_attribute_ids'])
 
             # Get user accounts
-            all_persons = Persons(self.api, person_ids)
+            all_persons = hashref(Persons(self.api, person_ids), 'person_id')
 
             key_ids = set()
             for person_id, person in all_persons.iteritems():
                 key_ids.update(person['key_ids'])
 
             # Get user account keys
-            all_keys = Keys(self.api, key_ids)
+            all_keys = hashref(Keys(self.api, key_ids), 'key_id')
 
             # Get slice attributes
-            all_slice_attributes = SliceAttributes(self.api, slice_attribute_ids)
+            all_slice_attributes = hashref(SliceAttributes(self.api, slice_attribute_ids), 'slice_attribute_id')
 
         nodes = []
         for node_id, node in all_nodes.iteritems():
             networks = [all_nodenetworks[nodenetwork_id] for nodenetwork_id in node['nodenetwork_ids']]
             nodegroups = [all_nodegroups[nodegroup_id] for nodegroup_id in node['nodegroup_ids']]
             groups = [nodegroup['name'] for nodegroup in nodegroups]
-            conf_files = dict([(conf_file['dest'], conf_file) for conf_file in all_conf_files.values()])
+
+            # If multiple entries for the same global configuration
+            # file exist, it is undefined which one takes precedence.
+            conf_files = {}
+            for conf_file in all_conf_files.values():
+                if not conf_file['node_ids'] and not conf_file['nodegroup_ids']:
+                    conf_files[conf_file['dest']] = conf_file
 
             # If a node belongs to multiple node
             # groups for which the same configuration file is defined,
             # it is undefined which one takes precedence.
             for nodegroup in nodegroups:
-                for conf_file in map(lambda id: all_conf_files[id], nodegroup['conf_file_ids']):
-                    conf_files[conf_file['dest']] = conf_file
+                for conf_file_id in nodegroup['conf_file_ids']:
+                    if conf_file_id in all_conf_files:
+                        conf_files[conf_file['dest']] = all_conf_files[conf_file_id]
 
             # Node configuration files always take precedence over
             # node group configuration files.
-            for conf_file in map(lambda id: all_conf_files[id], node['conf_file_ids']):
-                conf_files[conf_file['dest']] = conf_file
+            for conf_file_id in node['conf_file_ids']:
+                if conf_file_id in all_conf_files:
+                    conf_files[conf_file['dest']] = all_conf_files[conf_file_id]
 
             slivers = []
             for slice in map(lambda id: all_slices[id], node['slice_ids']):
index d7b4c83..3d5f4a0 100644 (file)
@@ -32,7 +32,7 @@ class RebootNode(Method):
 
     def call(self, auth, node_id_or_hostname):
         # Get account information
-        nodes = Nodes(self.api, [node_id_or_hostname]).values()
+        nodes = Nodes(self.api, [node_id_or_hostname])
         if not nodes:
             raise PLCInvalidArgument, "No such node"
 
@@ -55,7 +55,7 @@ class RebootNode(Method):
         # Only use the hostname as a backup, try to use the primary ID
         # address instead.
         host = node['hostname']
-        nodenetworks = NodeNetworks(self.api, node['nodenetwork_ids']).values()
+        nodenetworks = NodeNetworks(self.api, node['nodenetwork_ids'])
         for nodenetwork in nodenetworks:
             if nodenetwork['is_primary'] == 1:
                 host = nodenetwork['ip']
index 099b737..dd4e339 100644 (file)
@@ -68,7 +68,7 @@ class RefreshPeer(Method):
        foreign_nodes = ForeignNodes (self.api)
        
        ### mark entries for this peer outofdate
-       for foreign_node in foreign_nodes.values():
+       for foreign_node in foreign_nodes:
            if foreign_node['peer_id'] == peer_id:
                foreign_node.uptodate=False
 
@@ -99,5 +99,5 @@ class RefreshPeer(Method):
            foreign_nodes[hostname].sync()
 
        ### delete entries that are not uptodate
-       [ x.delete() for x in foreign_nodes.values() if not x.uptodate ]
+       [ x.delete() for x in foreign_nodes if not x.uptodate ]
        
index 1f7cd39..61ab287 100644 (file)
@@ -31,7 +31,7 @@ class SetPersonPrimarySite(Method):
         if not persons:
             raise PLCInvalidArgument, "No such account"
 
-        person = persons.values()[0]
+        person = persons[0]
 
         # Authenticated function
         assert self.caller is not None
@@ -46,7 +46,7 @@ class SetPersonPrimarySite(Method):
         if not sites:
             raise PLCInvalidArgument, "No such site"
 
-        site = sites.values()[0]
+        site = sites[0]
 
         if site['site_id'] not in person['site_ids']:
             raise PLCInvalidArgument, "Not a member of the specified site"
index e6b11a3..2fdc194 100644 (file)
@@ -34,7 +34,7 @@ class UpdateAddress(Method):
         address_fields = dict(filter(can_update, address_fields.items()))
 
         # Get associated address details
-        addresses = Addresses(self.api, [address_id]).values()
+        addresses = Addresses(self.api, [address_id])
         if not addresses:
             raise PLCInvalidArgument, "No such address"
         address = addresses[0]
index c4e9d52..a6309a6 100644 (file)
@@ -30,7 +30,7 @@ class UpdateAddressType(Method):
     def call(self, auth, address_type_id_or_name, address_type_fields):
         address_type_fields = dict(filter(can_update, address_type_fields.items()))
 
-        address_types = AddressTypes(self.api, [address_type_id_or_name]).values()
+        address_types = AddressTypes(self.api, [address_type_id_or_name])
         if not address_types:
             raise PLCInvalidArgument, "No such address type"
         address_type = address_types[0]
index 0963db7..7f9b8fc 100644 (file)
@@ -30,7 +30,7 @@ class UpdateConfFile(Method):
     def call(self, auth, conf_file_id, conf_file_fields):
         conf_file_fields = dict(filter(can_update, conf_file_fields.items()))
 
-        conf_files = ConfFiles(self.api, [conf_file_id]).values()
+        conf_files = ConfFiles(self.api, [conf_file_id])
         if not conf_files:
             raise PLCInvalidArgument, "No such configuration file"
 
index 19acbe3..5f6ecc4 100644 (file)
@@ -33,7 +33,7 @@ class UpdateKey(Method):
         key_fields = dict(filter(can_update, key_fields.items()))
 
         # Get key information
-        keys = Keys(self.api, [key_id]).values()
+        keys = Keys(self.api, [key_id])
         if not keys:
             raise PLCInvalidArgument, "No such key"
         key = keys[0]
index 261eaeb..f28ce12 100644 (file)
@@ -31,7 +31,7 @@ class UpdateMessage(Method):
         message_fields = dict(filter(can_update, message_fields.items()))
 
         # Get message information
-        messages = Messages(self.api, [message_id]).values()
+        messages = Messages(self.api, [message_id])
         if not messages:
             raise PLCInvalidArgument, "No such message"
         message = messages[0]
index 9bfb8dc..ae42bb0 100644 (file)
@@ -45,7 +45,7 @@ class UpdateNode(Method):
         if not nodes:
             raise PLCInvalidArgument, "No such node"
 
-        node = nodes.values()[0]
+        node = nodes[0]
 
         # Authenticated function
         assert self.caller is not None
index 6ef1146..f655c67 100644 (file)
@@ -34,7 +34,7 @@ class UpdateNodeGroup(Method):
        nodegroups = NodeGroups(self.api, [nodegroup_id_or_name])
        if not nodegroups:
             raise PLCInvalidArgument, "No such nodegroup"
-       nodegroup = nodegroups.values()[0]
+       nodegroup = nodegroups[0]
        
        nodegroup.update(nodegroup_fields)
         nodegroup.sync()
index ca1e91f..c4df647 100644 (file)
@@ -40,7 +40,7 @@ class UpdateNodeNetwork(Method):
         nodenetwork_fields = dict(filter(can_update, nodenetwork_fields.items()))
 
        # Get node network information
-       nodenetworks = NodeNetworks(self.api, [nodenetwork_id_or_ip]).values()
+       nodenetworks = NodeNetworks(self.api, [nodenetwork_id_or_ip])
        if not nodenetworks:
             raise PLCInvalidArgument, "No such node network"
 
@@ -52,7 +52,7 @@ class UpdateNodeNetwork(Method):
        # If we are not an admin, make sure that the caller is a
         # member of the site where the node exists.
         if 'admin' not in self.caller['roles']:
-            nodes = Nodes(self.api, [nodenetwork['node_id']]).values()
+            nodes = Nodes(self.api, [nodenetwork['node_id']])
             if not nodes:
                 raise PLCPermissionDenied, "Node network is not associated with a node"
             node = nodes[0]
index 5980f0c..e22227b 100644 (file)
@@ -33,7 +33,7 @@ class UpdatePCU(Method):
         pcu_fields = dict(filter(can_update, pcu_fields.items()))
 
         # Get associated PCU details
-        pcus = PCUs(self.api, [pcu_id]).values()
+        pcus = PCUs(self.api, [pcu_id])
         if not pcus:
             raise PLCInvalidArgument, "No such PCU"
         pcu = pcus[0]
index 71c47bf..7f769f5 100644 (file)
@@ -41,7 +41,7 @@ class UpdatePerson(Method):
         if not persons:
             raise PLCInvalidArgument, "No such account"
 
-        person = persons.values()[0]
+        person = persons[0]
 
         # Authenticated function
         assert self.caller is not None
index 7f79f09..776b084 100644 (file)
@@ -41,7 +41,7 @@ class UpdateSite(Method):
         if not sites:
             raise PLCInvalidArgument, "No such site"
 
-        site = sites.values()[0]
+        site = sites[0]
 
         # Authenticated function
         assert self.caller is not None
index f6c9943..5ac3abc 100644 (file)
@@ -42,7 +42,7 @@ class UpdateSlice(Method):
     def call(self, auth, slice_id_or_name, slice_fields):
         slice_fields = dict(filter(can_update, slice_fields.items()))
 
-        slices = Slices(self.api, [slice_id_or_name]).values()
+        slices = Slices(self.api, [slice_id_or_name])
         if not slices:
             raise PLCInvalidArgument, "No such slice"
         slice = slices[0]
@@ -57,7 +57,7 @@ class UpdateSlice(Method):
 
         # Renewing
         if 'expires' in slice_fields and slice_fields['expires'] > slice['expires']:
-            sites = Sites(self.api, [slice['site_id']]).values()
+            sites = Sites(self.api, [slice['site_id']])
             assert sites
             site = sites[0]
 
index 5557ad0..a9e2ff5 100644 (file)
@@ -28,12 +28,12 @@ class UpdateSliceAttribute(Method):
     returns = Parameter(int, '1 if successful')
 
     def call(self, auth, slice_attribute_id, value):
-        slice_attributes = SliceAttributes(self.api, [slice_attribute_id]).values()
+        slice_attributes = SliceAttributes(self.api, [slice_attribute_id])
         if not slice_attributes:
             raise PLCInvalidArgument, "No such slice attribute"
         slice_attribute = slice_attributes[0]
 
-        slices = Slices(self.api, [slice_attribute['slice_id']]).values()
+        slices = Slices(self.api, [slice_attribute['slice_id']])
         if not slices:
             raise PLCInvalidArgument, "No such slice"
         slice = slices[0]
index df3224c..2767e60 100644 (file)
@@ -31,7 +31,7 @@ class UpdateSliceAttributeType(Method):
     def call(self, auth, attribute_type_id_or_name, attribute_type_fields):
         attribute_type_fields = dict(filter(can_update, attribute_type_fields.items()))
 
-        attribute_types = SliceAttributeTypes(self.api, [attribute_type_id_or_name]).values()
+        attribute_types = SliceAttributeTypes(self.api, [attribute_type_id_or_name])
         if not attribute_types:
             raise PLCInvalidArgument, "No such attribute"
         attribute_type = attribute_types[0]
index 550d0bd..90bd5f9 100644 (file)
@@ -4,7 +4,7 @@
 # Mark Huang <mlhuang@cs.princeton.edu>
 # Copyright (C) 2006 The Trustees of Princeton University
 #
-# $Id: NodeGroups.py,v 1.17 2006/11/08 22:59:15 mlhuang Exp $
+# $Id: NodeGroups.py,v 1.18 2006/11/09 03:07:42 mlhuang Exp $
 #
 
 from types import StringTypes
@@ -104,11 +104,11 @@ class NodeGroups(Table):
     database.
     """
 
-    def __init__(self, api, nodegroup_filter = None):
-        Table.__init__(self, api, NodeGroup)
+    def __init__(self, api, nodegroup_filter = None, columns = None):
+        Table.__init__(self, api, NodeGroup, columns)
 
         sql = "SELECT %s FROM view_nodegroups WHERE True" % \
-              ", ".join(NodeGroup.fields)
+              ", ".join(self.columns)
 
         if nodegroup_filter is not None:
             if isinstance(nodegroup_filter, (list, tuple, set)):
index 1d4518b..a5a0f9d 100644 (file)
@@ -4,7 +4,7 @@
 # Mark Huang <mlhuang@cs.princeton.edu>
 # Copyright (C) 2006 The Trustees of Princeton University
 #
-# $Id: NodeNetworks.py,v 1.13 2006/11/08 22:59:34 mlhuang Exp $
+# $Id: NodeNetworks.py,v 1.14 2006/11/09 03:07:42 mlhuang Exp $
 #
 
 from types import StringTypes
@@ -67,12 +67,14 @@ class NodeNetwork(Row):
         }
 
     def validate_method(self, method):
-        if method not in NetworkMethods(self.api):
+        network_methods = [row['method'] for row in NetworkMethods(self.api)]
+        if method not in network_methods:
             raise PLCInvalidArgument, "Invalid addressing method"
        return method
 
     def validate_type(self, type):
-        if type not in NetworkTypes(self.api):
+        network_types = [row['type'] for row in NetworkTypes(self.api)]
+        if type not in network_types:
             raise PLCInvalidArgument, "Invalid address type"
        return type
 
@@ -130,15 +132,16 @@ class NodeNetwork(Row):
         """
 
         if is_primary:
-            nodes = PLC.Nodes.Nodes(self.api, [self['node_id']]).values()
+            nodes = PLC.Nodes.Nodes(self.api, [self['node_id']])
             if not nodes:
                 raise PLCInvalidArgument, "No such node"
             node = nodes[0]
 
             if node['nodenetwork_ids']:
                 conflicts = NodeNetworks(self.api, node['nodenetwork_ids'])
-                for nodenetwork_id, nodenetwork in conflicts.iteritems():
-                    if ('nodenetwork_id' not in self or self['nodenetwork_id'] != nodenetwork_id) and \
+                for nodenetwork in conflicts:
+                    if ('nodenetwork_id' not in self or \
+                        self['nodenetwork_id'] != nodenetwork['nodenetwork_id']) and \
                        nodenetwork['is_primary']:
                         raise PLCInvalidArgument, "Can only set one primary interface per node"
 
@@ -192,11 +195,11 @@ class NodeNetworks(Table):
     database.
     """
 
-    def __init__(self, api, nodenetwork_filter = None):
-        Table.__init__(self, api, NodeNetwork)
+    def __init__(self, api, nodenetwork_filter = None, columns = None):
+        Table.__init__(self, api, NodeNetwork, columns)
 
         sql = "SELECT %s FROM nodenetworks WHERE True" % \
-              ", ".join(NodeNetwork.fields)
+              ", ".join(self.columns)
 
         if nodenetwork_filter is not None:
             if isinstance(nodenetwork_filter, (list, tuple, set)):
index fee73eb..ae2a5e7 100644 (file)
@@ -4,7 +4,7 @@
 # Mark Huang <mlhuang@cs.princeton.edu>
 # Copyright (C) 2006 The Trustees of Princeton University
 #
-# $Id: Nodes.py,v 1.18 2006/11/08 23:13:11 mlhuang Exp $
+# $Id: Nodes.py,v 1.19 2006/11/09 03:07:42 mlhuang Exp $
 #
 
 from types import StringTypes
@@ -66,14 +66,15 @@ class Node(Row):
             raise PLCInvalidArgument, "Invalid hostname"
 
         conflicts = Nodes(self.api, [hostname])
-        for node_id, node in conflicts.iteritems():
-            if 'node_id' not in self or self['node_id'] != node_id:
+        for node in conflicts:
+            if 'node_id' not in self or self['node_id'] != node['node_id']:
                 raise PLCInvalidArgument, "Hostname already in use"
 
         return hostname
 
     def validate_boot_state(self, boot_state):
-        if boot_state not in BootStates(self.api):
+        boot_states = [row['boot_state'] for row in BootStates(self.api)]
+        if boot_state not in boot_states:
             raise PLCInvalidArgument, "Invalid boot state"
 
         return boot_state
@@ -100,11 +101,11 @@ class Nodes(Table):
     database.
     """
 
-    def __init__(self, api, node_filter = None):
-        Table.__init__(self, api, Node)
+    def __init__(self, api, node_filter = None, columns = None):
+        Table.__init__(self, api, Node, columns)
 
         sql = "SELECT %s FROM view_nodes WHERE deleted IS False" % \
-              ", ".join(Node.fields)
+              ", ".join(self.columns)
 
         if node_filter is not None:
             if isinstance(node_filter, (list, tuple, set)):
index 2bace8b..5b69c0a 100644 (file)
@@ -4,7 +4,7 @@
 # Mark Huang <mlhuang@cs.princeton.edu>
 # Copyright (C) 2006 The Trustees of Princeton University
 #
-# $Id: PCUs.py,v 1.8 2006/11/08 23:00:00 mlhuang Exp $
+# $Id: PCUs.py,v 1.9 2006/11/09 03:07:42 mlhuang Exp $
 #
 
 from PLC.Faults import *
@@ -100,11 +100,11 @@ class PCUs(Table):
     database.
     """
 
-    def __init__(self, api, pcu_filter = None):
-        Table.__init__(self, api, PCU)
+    def __init__(self, api, pcu_filter = None, columns = None):
+        Table.__init__(self, api, PCU, columns)
 
         sql = "SELECT %s FROM view_pcus WHERE True" % \
-              ", ".join(PCU.fields)
+              ", ".join(self.columns)
 
         if pcu_filter is not None:
             if isinstance(pcu_filter, (list, tuple, set)):
index 1a5e6fb..8be0521 100644 (file)
@@ -51,11 +51,11 @@ class Peers (Table):
     Maps to the peers table in the database
     """
     
-    def __init__ (self, api, peer_filter = None):
-        Table.__init__(self, api, Peer)
+    def __init__ (self, api, peer_filter = None, columns = None):
+        Table.__init__(self, api, Peer, columns)
 
        sql = "SELECT %s FROM view_peers WHERE deleted IS False" % \
-              ", ".join(Peer.fields)
+              ", ".join(self.columns)
 
         if peer_filter is not None:
             if isinstance(peer_filter, (list, tuple, set)):
index c61e8bd..305c1ec 100644 (file)
@@ -4,7 +4,7 @@
 # Mark Huang <mlhuang@cs.princeton.edu>
 # Copyright (C) 2006 The Trustees of Princeton University
 #
-# $Id: Persons.py,v 1.17 2006/11/08 22:45:20 mlhuang Exp $
+# $Id: Persons.py,v 1.18 2006/11/09 03:07:42 mlhuang Exp $
 #
 
 from types import StringTypes
@@ -81,8 +81,8 @@ class Person(Row):
             raise invalid_email
 
         conflicts = Persons(self.api, [email])
-        for person_id, person in conflicts.iteritems():
-            if 'person_id' not in self or self['person_id'] != person_id:
+        for person in conflicts:
+            if 'person_id' not in self or self['person_id'] != person['person_id']:
                 raise PLCInvalidArgument, "E-mail address already in use"
 
         return email
@@ -272,7 +272,7 @@ class Person(Row):
 
         # Delete all keys
         keys = Keys(self.api, self['key_ids'])
-        for key in keys.values():
+        for key in keys:
             key.delete(commit = False)
 
         # Clean up miscellaneous join tables
@@ -290,11 +290,11 @@ class Persons(Table):
     database.
     """
 
-    def __init__(self, api, person_filter = None):
-        Table.__init__(self, api, Person)
+    def __init__(self, api, person_filter = None, columns = None):
+        Table.__init__(self, api, Person, columns)
 
         sql = "SELECT %s FROM view_persons WHERE deleted IS False" % \
-              ", ".join(Person.fields)
+              ", ".join(self.columns)
 
         if person_filter is not None:
             if isinstance(person_filter, (list, tuple, set)):
index f45ea97..305e55b 100644 (file)
@@ -79,7 +79,7 @@ class Session(Row):
     def sync(self, commit = True, insert = None):
         if not self.has_key('session_id'):
             # Before a new session is added, delete expired sessions
-            expired = Sessions(self.api, expires = -int(time.time())).values()
+            expired = Sessions(self.api, expires = -int(time.time()))
             for session in expired:
                 session.delete(commit)
 
index 2ac28a8..7474f03 100644 (file)
@@ -58,8 +58,8 @@ class Site(Row):
             raise PLCInvalidArgument, "Login base must consist only of lowercase ASCII letters"
 
         conflicts = Sites(self.api, [login_base])
-        for site_id, site in conflicts.iteritems():
-            if 'site_id' not in self or self['site_id'] != site_id:
+        for site in conflicts:
+            if 'site_id' not in self or self['site_id'] != site['site_id']:
                 raise PLCInvalidArgument, "login_base already in use"
 
         return login_base
@@ -184,12 +184,12 @@ class Site(Row):
         # Delete accounts of all people at the site who are not
         # members of at least one other non-deleted site.
         persons = PLC.Persons.Persons(self.api, self['person_ids'])
-        for person_id, person in persons.iteritems():
+        for person in persons:
             delete = True
 
             person_sites = Sites(self.api, person['site_ids'])
-            for person_site_id, person_site in person_sites.iteritems():
-                if person_site_id != self['site_id']:
+            for person_site in person_sites:
+                if person_site['site_id'] != self['site_id']:
                     delete = False
                     break
 
@@ -198,22 +198,22 @@ class Site(Row):
 
         # Delete all site addresses
         addresses = Addresses(self.api, self['address_ids'])
-        for address in addresses.values():
-           address.delete(commit = False)
+        for address in addresses:
+            address.delete(commit = False)
 
         # Delete all site slices
         slices = Slices(self.api, self['slice_ids'])
-        for slice in slices.values():
-           slice.delete(commit = False)
+        for slice in slices:
+            slice.delete(commit = False)
 
         # Delete all site PCUs
         pcus = PCUs(self.api, self['pcu_ids'])
-        for pcu in pcus.values():
-           pcu.delete(commit = False)
+        for pcu in pcus:
+            pcu.delete(commit = False)
 
         # Delete all site nodes
         nodes = Nodes(self.api, self['node_ids'])
-        for node in nodes.values():
+        for node in nodes:
             node.delete(commit = False)
 
         # Clean up miscellaneous join tables
@@ -232,11 +232,11 @@ class Sites(Table):
     database.
     """
 
-    def __init__(self, api, site_filter = None):
-        Table.__init__(self, api, Site)
+    def __init__(self, api, site_filter = None, columns = None):
+        Table.__init__(self, api, Site, columns)
 
         sql = "SELECT %s FROM view_sites WHERE deleted IS False" % \
-              ", ".join(Site.fields)
+              ", ".join(self.columns)
 
         if site_filter is not None:
             if isinstance(site_filter, (list, tuple, set)):
index 7175fef..4fa0ff8 100644 (file)
@@ -27,14 +27,15 @@ class SliceAttributeType(Row):
             raise PLCInvalidArgument, "Slice attribute type name must be set"
 
         conflicts = SliceAttributeTypes(self.api, [name])
-        for attribute_type_id, attribute in conflicts.iteritems():
-            if 'attribute_type_id' not in self or self['attribute_type_id'] != attribute_type_id:
+        for attribute in conflicts:
+            if 'attribute_type_id' not in self or \
+               self['attribute_type_id'] != attribute['attribute_type_id']:
                 raise PLCInvalidArgument, "Slice attribute type name already in use"
 
         return name
 
     def validate_min_role_id(self, role_id):
-        roles = Roles(self.api)
+        roles = [row['role_id'] for row in Roles(self.api)]
         if role_id not in roles:
             raise PLCInvalidArgument, "Invalid role"
 
@@ -46,11 +47,11 @@ class SliceAttributeTypes(Table):
     database.
     """
 
-    def __init__(self, api, attribute_type_filter = None):
-        Table.__init__(self, api, SliceAttributeType)
+    def __init__(self, api, attribute_type_filter = None, columns = None):
+        Table.__init__(self, api, SliceAttributeType, columns)
 
         sql = "SELECT %s FROM slice_attribute_types WHERE True" % \
-              ", ".join(SliceAttributeType.fields)
+              ", ".join(self.columns)
 
         if attribute_type_filter is not None:
             if isinstance(attribute_type_filter, (list, tuple, set)):
index fffb8bb..2788b72 100644 (file)
@@ -30,11 +30,11 @@ class SliceAttributes(Table):
     database.
     """
 
-    def __init__(self, api, slice_attribute_filter = None):
-        Table.__init__(self, api, SliceAttribute)
+    def __init__(self, api, slice_attribute_filter = None, columns = None):
+        Table.__init__(self, api, SliceAttribute, columns)
 
         sql = "SELECT %s FROM view_slice_attributes WHERE True" % \
-              ", ".join(SliceAttribute.fields)
+              ", ".join(self.columns)
 
         if slice_attribute_filter is not None:
             if isinstance(slice_attribute_filter, (list, tuple, set)):
index 13e0842..e62bd63 100644 (file)
@@ -53,14 +53,14 @@ class Slice(Row):
             raise PLCInvalidArgument, "Invalid slice name"
 
         conflicts = Slices(self.api, [name])
-        for slice_id, slice in conflicts.iteritems():
-            if 'slice_id' not in self or self['slice_id'] != slice_id:
+        for slice in conflicts:
+            if 'slice_id' not in self or self['slice_id'] != slice['slice_id']:
                 raise PLCInvalidArgument, "Slice name already in use"
 
         return name
 
     def validate_instantiation(self, instantiation):
-        instantiations = SliceInstantiations(self.api)
+        instantiations = [row['instantiation'] for row in SliceInstantiations(self.api)]
         if instantiation not in instantiations:
             raise PLCInvalidArgument, "No such instantiation state"
 
@@ -186,7 +186,7 @@ class Slice(Row):
 
         # Before a new slice is added, delete expired slices
         if 'slice_id' not in self:
-            expired = Slices(self.api, expires = -int(time.time())).values()
+            expired = Slices(self.api, expires = -int(time.time()))
             for slice in expired:
                 slice.delete(commit)
 
@@ -215,11 +215,11 @@ class Slices(Table):
     database.
     """
 
-    def __init__(self, api, slice_filter = None, expires = int(time.time())):
-        Table.__init__(self, api, Slice)
+    def __init__(self, api, slice_filter = None, columns = None, expires = int(time.time())):
+        Table.__init__(self, api, Slice, columns)
 
         sql = "SELECT %s FROM view_slices WHERE is_deleted IS False" % \
-              ", ".join(Slice.fields)
+              ", ".join(self.columns)
 
         if expires is not None:
             if expires >= 0:
index ae526b5..967bc6d 100644 (file)
@@ -118,29 +118,37 @@ class Row(dict):
         if commit:
             self.api.db.commit()
 
-class Table(dict):
+class Table(list):
     """
     Representation of row(s) in a database table.
     """
 
-    def __init__(self, api, row):
+    def __init__(self, api, row, columns = None):
         self.api = api
         self.row = row
 
+        if columns is None:
+            columns = row.fields
+        else:
+            columns = filter(lambda x: x in row.fields, columns)
+            if not columns:
+                raise PLCInvalidArgument, "No valid return fields specified"
+
+        self.columns = columns
+
     def sync(self, commit = True):
         """
         Flush changes back to the database.
         """
 
-        for row in self.values():
+        for row in self:
             row.sync(commit)
 
     def selectall(self, sql, params = None):
         """
         Given a list of rows from the database, fill ourselves with
-        Row objects keyed on the primary key defined by the Row class
-        we were initialized with.
+        Row objects.
         """
 
         for row in self.api.db.selectall(sql, params):
-            self[row[self.row.primary_key]] = self.row(self.api, row)
+            self.append(self.row(self.api, row))