bug fixes
authorTony Mack <tmack@paris.CS.Princeton.EDU>
Thu, 11 Oct 2012 18:09:06 +0000 (14:09 -0400)
committerTony Mack <tmack@paris.CS.Princeton.EDU>
Thu, 11 Oct 2012 18:09:06 +0000 (14:09 -0400)
27 files changed:
PLC/API.py
PLC/GPG.py
PLC/InterfaceTags.py
PLC/Keys.py
PLC/Methods/AddNode.py
PLC/Methods/AddNodeGroup.py
PLC/Methods/AddPCUType.py
PLC/Methods/AddRoleToPerson.py
PLC/Methods/BootNotifyOwners.py
PLC/Methods/DeleteRoleFromTagType.py
PLC/Methods/GetBootMedium.py
PLC/Methods/GetNodeFlavour.py
PLC/Methods/GetPersons.py
PLC/Methods/GetSliceFamily.py
PLC/Methods/GetSlivers.py
PLC/Methods/UpdateKey.py
PLC/Methods/UpdateNode.py
PLC/Methods/UpdatePerson.py
PLC/Methods/UpdateSite.py
PLC/Methods/UpdateSlice.py
PLC/NodeGroups.py
PLC/Nodes.py
PLC/PCUTypes.py
PLC/PersonTags.py
PLC/Shell.py
PLC/Slices.py
PLCAPI.spec

index 16d3a61..cd0520b 100644 (file)
@@ -171,7 +171,8 @@ class PLCAPI:
             module = __import__(fullpath, globals(), locals(), [classname])
             return getattr(module, classname)(self)
         except ImportError, AttributeError:
             module = __import__(fullpath, globals(), locals(), [classname])
             return getattr(module, classname)(self)
         except ImportError, AttributeError:
-            raise PLCInvalidAPIMethod, "import error %s for %s" % (AttributeError,fullpath)
+            raise
+            #raise PLCInvalidAPIMethod, "import error %s for %s" % (AttributeError,fullpath)
 
     def call(self, source, method, *args):
         """
 
     def call(self, source, method, *args):
         """
index ffecff0..f239741 100644 (file)
@@ -14,7 +14,8 @@ import shutil
 from types import StringTypes
 from StringIO import StringIO
 from xml.dom import minidom
 from types import StringTypes
 from StringIO import StringIO
 from xml.dom import minidom
-from xml.dom.ext import Canonicalize
+import lxml
+from lxml import etree
 from subprocess import Popen, PIPE, call
 from tempfile import NamedTemporaryFile, mkdtemp
 
 from subprocess import Popen, PIPE, call
 from tempfile import NamedTemporaryFile, mkdtemp
 
@@ -28,17 +29,10 @@ def canonicalize(args, methodname = None, methodresponse = False):
     """
 
     xml = xmlrpclib.dumps(args, methodname, methodresponse, encoding = 'utf-8', allow_none = 1)
     """
 
     xml = xmlrpclib.dumps(args, methodname, methodresponse, encoding = 'utf-8', allow_none = 1)
-    dom = minidom.parseString(xml)
-
-    # Canonicalize(), though it claims to, does not encode unicode
-    # nodes to UTF-8 properly and throws an exception unless you write
-    # the stream to a file object, so just encode it ourselves.
-    buf = StringIO()
-    Canonicalize(dom, output = buf)
-    xml = buf.getvalue().encode('utf-8')
-
-    return xml
-
+    parser = etree.XMLParser(remove_blank_text=True)        
+    tree = etree.parse(StringIO(xml), parser)
+    return etree.tostring(tree.getroot(), method='c14n')
 def gpg_export(keyring, armor = True):
     """
     Exports the specified public keyring file.
 def gpg_export(keyring, armor = True):
     """
     Exports the specified public keyring file.
index 4ed6e96..3c0644e 100644 (file)
@@ -56,7 +56,7 @@ class InterfaceTags(list):
         if isinstance(interface_tag_filter, (list, tuple, set, int, long)):
             interface_tags = InterfaceTag().select(filter={'interface_tag_id': interface_tag_filter})
         elif isinstance(interface_tag_filter, dict):
         if isinstance(interface_tag_filter, (list, tuple, set, int, long)):
             interface_tags = InterfaceTag().select(filter={'interface_tag_id': interface_tag_filter})
         elif isinstance(interface_tag_filter, dict):
-            interface_tags = InterfaceTag().select(filter=interface_tag_filter})
+            interface_tags = InterfaceTag().select(filter=interface_tag_filter)
         else:
             raise PLCInvalidArgument, "Wrong interface setting filter %r"%interface_tag_filter
 
         else:
             raise PLCInvalidArgument, "Wrong interface setting filter %r"%interface_tag_filter
 
index 6f82838..c174470 100644 (file)
@@ -6,9 +6,9 @@ from PLC.Filter import Filter
 from PLC.Debug import profile
 from PLC.Table import Row, Table
 from PLC.KeyTypes import KeyType, KeyTypes
 from PLC.Debug import profile
 from PLC.Table import Row, Table
 from PLC.KeyTypes import KeyType, KeyTypes
-from PLC.NovaTable import NovaObject, NovaTable
+from PLC.Storage.AlchemyObject import AlchemyObj
 
 
-class Key(NovaObject):
+class Key(AlchemyObj):
     """
     Representation of a row in the keys table. To use, instantiate with a
     dict of values. Update as you would a dict. Commit to the database
     """
     Representation of a row in the keys table. To use, instantiate with a
     dict of values. Update as you would a dict. Commit to the database
@@ -16,24 +16,30 @@ class Key(NovaObject):
     """
 
     tablename = 'keys'
     """
 
     tablename = 'keys'
-    join_tables = ['person_key', 'peer_key']
     fields = {
     fields = {
-        'id': Parameter(str, "Key identifier", primary_key=True),
-        #'key_type': Parameter(str, "Key type"),
-        'public_key': Parameter(str, "Key string", max = 4096),
-        'name': Parameter(str, "Key name",)
+        'key_id': Parameter(str, "Key identifier", primary_key=True),
+        'key_type': Parameter(str, "Key type"),
+        'key': Parameter(str, "Key string", max = 4096), # backwards compatibility
+        'name': Parameter(str, "Key name"),
+        'uuid': Parameter(str, "Key name", ro=True)
         }
 
         }
 
-    def sync(self, insert = False, validate = True):
-        NovaObject.sync(self, insert, validate)
-        if insert == True or 'id' not in self:
-            self.object = self.api.client_shell.nova.keypairs.create(self.id,
-                                                                     self.key)
-        else:
-            self.object = self.api.client_shell.nova.keypairs.update(self.id, dict(self))
+    def sync(self, commit = True, validate = True):
+        # sync the nova record and the plc record
+        assert 'key' in self
+        assert 'name' in self
+        AlchemyObj.sync(self, commit=commit, validate=validate)
+        nova_key = {
+            'public_key': self['key'],
+            'name': self['name'] 
+        }
+        self.object = self.api.client_shell.nova.keypairs.create(**nova_key)
+        self['uuid'] = self.object.uuid
+        AlchemyObj.insert(self, dict(self))
 
     def delete(self):
 
     def delete(self):
-        assert 'id' in self
+        assert 'key_id' in self
+        assert 'name' in self
         self.api.client_shell.nova.keypairs.delete(self.id)
 
     def validate_public_key(self, key):
         self.api.client_shell.nova.keypairs.delete(self.id)
 
     def validate_public_key(self, key):
@@ -79,26 +85,9 @@ class Key(NovaObject):
         assert 'key_id' in self
         assert 'key' in self
 
         assert 'key_id' in self
         assert 'key' in self
 
-        # Get all matching keys
-        rows = self.api.db.selectall("SELECT key_id FROM keys WHERE key = %(key)s",
-                                     self)
-        key_ids = [row['key_id'] for row in rows]
-        assert key_ids
-        assert self['key_id'] in key_ids
-
-        # Keep the keys in the table
-        self.api.db.do("UPDATE keys SET is_blacklisted = True" \
-                       " WHERE key_id IN (%s)" % ", ".join(map(str, key_ids)))
-
-        # But disassociate them from all join tables
-        for table in self.join_tables:
-            self.api.db.do("DELETE FROM %s WHERE key_id IN (%s)" % \
-                           (table, ", ".join(map(str, key_ids))))
-
-        if commit:
-            self.api.db.commit()
+        pass
 
 
-class Keys(NovaTable):
+class Keys(list):
     """
     Representation of row(s) from the keys table in the
     database.
     """
     Representation of row(s) from the keys table in the
     database.
index 3a5ce90..830444e 100644 (file)
@@ -10,7 +10,8 @@ from PLC.NodeTags import NodeTags, NodeTag
 from PLC.Methods.AddNodeTag import AddNodeTag
 from PLC.Methods.UpdateNodeTag import UpdateNodeTag
 
 from PLC.Methods.AddNodeTag import AddNodeTag
 from PLC.Methods.UpdateNodeTag import UpdateNodeTag
 
-can_update = ['hostname', 'node_type', 'boot_state', 'model', 'version']
+can_update = lambda (field, value): field in \
+            ['hostname', 'node_type', 'boot_state', 'model', 'version']
 
 class AddNode(Method):
     """
 
 class AddNode(Method):
     """
@@ -25,8 +26,7 @@ class AddNode(Method):
 
     roles = ['admin', 'pi', 'tech']
 
 
     roles = ['admin', 'pi', 'tech']
 
-    accepted_fields = Row.accepted_fields(can_update,Node.fields)
-    accepted_fields.update(Node.tags)
+    accepted_fields = dict(filter(can_update, Node.fields.items()))
 
     accepts = [
         Auth(),
 
     accepts = [
         Auth(),
@@ -39,13 +39,6 @@ class AddNode(Method):
 
     def call(self, auth, site_id_or_login_base, node_fields):
 
 
     def call(self, auth, site_id_or_login_base, node_fields):
 
-        [native,tags,rejected]=Row.split_fields(node_fields,[Node.fields,Node.tags])
-
-        # type checking
-        native = Row.check_fields(native, self.accepted_fields)
-        if rejected:
-            raise PLCInvalidArgument, "Cannot add Node with column(s) %r"%rejected
-
         # Get site information
         sites = Sites(self.api, [site_id_or_login_base])
         if not sites:
         # Get site information
         sites = Sites(self.api, [site_id_or_login_base])
         if not sites:
@@ -65,13 +58,15 @@ class AddNode(Method):
             else:
                 assert self.caller['person_id'] in site['person_ids']
 
             else:
                 assert self.caller['person_id'] in site['person_ids']
 
-        node = Node(self.api, native)
+        node_fields = dict(filter(can_update, node_fields.items()))
+        node = Node(self.api, node_fields)
         node['site_id'] = site['site_id']
         node.sync()
 
         # since hostname was specified lets add the 'hrn' node tag
         root_auth = self.api.config.PLC_HRN_ROOT
         login_base = site['login_base']
         node['site_id'] = site['site_id']
         node.sync()
 
         # since hostname was specified lets add the 'hrn' node tag
         root_auth = self.api.config.PLC_HRN_ROOT
         login_base = site['login_base']
+        tags={}
         tags['hrn'] = hostname_to_hrn(root_auth, login_base, node['hostname'])
 
         for (tagname,value) in tags.iteritems():
         tags['hrn'] = hostname_to_hrn(root_auth, login_base, node['hostname'])
 
         for (tagname,value) in tags.iteritems():
@@ -93,8 +88,5 @@ class AddNode(Method):
                 node_tag['value'] = value
                 node_tag.sync() 
 
                 node_tag['value'] = value
                 node_tag.sync() 
 
-        self.event_objects = {'Site': [site['site_id']],
-                              'Node': [node['node_id']]}
-        self.message = "Node %d=%s created" % (node['node_id'],node['hostname'])
 
         return node['node_id']
 
         return node['node_id']
index a24fa8e..505327f 100644 (file)
@@ -7,7 +7,7 @@ from PLC.NodeGroups import NodeGroup, NodeGroups
 from PLC.TagTypes import TagType, TagTypes
 from PLC.NodeTags import NodeTag, NodeTags
 
 from PLC.TagTypes import TagType, TagTypes
 from PLC.NodeTags import NodeTag, NodeTags
 
-can_update = lambda (field, value): field in NodeGroup.fields.keys() and field != NodeGroup.primary_field
+can_update = lambda (field, value): field in NodeGroup.fields.keys() and field not in [NodeGroup.fields['nodegroup_id']] 
 
 class AddNodeGroup(Method):
     """
 
 class AddNodeGroup(Method):
     """
index 2c8fbe5..1037883 100644 (file)
@@ -30,6 +30,5 @@ class AddPCUType(Method):
         pcu_type_fields = dict(filter(can_update, pcu_type_fields.items()))
         pcu_type = PCUType(self.api, pcu_type_fields)
         pcu_type.sync()
         pcu_type_fields = dict(filter(can_update, pcu_type_fields.items()))
         pcu_type = PCUType(self.api, pcu_type_fields)
         pcu_type.sync()
-        self.event_object = {'PCUType': [pcu_type['pcu_type_id']]}
 
         return pcu_type['pcu_type_id']
 
         return pcu_type['pcu_type_id']
index 1e47033..3fc1df3 100644 (file)
@@ -19,7 +19,7 @@ class AddRoleToPerson(Method):
 
     accepts = [
         Auth(),
 
     accepts = [
         Auth(),
-        Mixed(Role.fields['role_id'],
+        Mixed(Role.fields['id'],
               Role.fields['name']),
         Mixed(Person.fields['person_id'],
               Person.fields['email']),
               Role.fields['name']),
         Mixed(Person.fields['person_id'],
               Person.fields['email']),
@@ -40,9 +40,6 @@ class AddRoleToPerson(Method):
             raise PLCInvalidArgument, "No such account"
         person = persons[0]
 
             raise PLCInvalidArgument, "No such account"
         person = persons[0]
 
-        if person['peer_id'] is not None:
-            raise PLCInvalidArgument, "Not a local account"
-
         # Authenticated function
         assert self.caller is not None
 
         # Authenticated function
         assert self.caller is not None
 
@@ -58,9 +55,4 @@ class AddRoleToPerson(Method):
         if role['role_id'] not in person['role_ids']:
             person.add_role(role)
 
         if role['role_id'] not in person['role_ids']:
             person.add_role(role)
 
-        self.event_objects = {'Person': [person['person_id']],
-                              'Role': [role['role_id']]}
-        self.message = "Role %d granted to person %d" % \
-                       (role['role_id'], person['person_id'])
-
         return 1
         return 1
index 7458b9d..13799f7 100644 (file)
@@ -1,6 +1,6 @@
 from PLC.Method import Method
 from PLC.Parameter import Parameter, Mixed
 from PLC.Method import Method
 from PLC.Parameter import Parameter, Mixed
-from PLC.Auth import Auth, BootAuth, SessionAuth
+from PLC.Auth import Auth
 from PLC.Nodes import Node, Nodes
 from PLC.Messages import Message, Messages
 
 from PLC.Nodes import Node, Nodes
 from PLC.Messages import Message, Messages
 
index cdce6fa..db009d2 100644 (file)
@@ -19,7 +19,7 @@ class DeleteRoleFromTagType(Method):
 
     accepts = [
         Auth(),
 
     accepts = [
         Auth(),
-        Mixed(Role.fields['role_id'],
+        Mixed(Role.fields['id'],
               Role.fields['name']),
         Mixed(TagType.fields['tag_type_id'],
               TagType.fields['tagname']),
               Role.fields['name']),
         Mixed(TagType.fields['tag_type_id'],
               TagType.fields['tagname']),
index 7225b12..b1380db 100644 (file)
@@ -14,7 +14,7 @@ from PLC.Interfaces import Interface, Interfaces
 from PLC.InterfaceTags import InterfaceTag, InterfaceTags
 from PLC.NodeTags import NodeTag, NodeTags
 
 from PLC.InterfaceTags import InterfaceTag, InterfaceTags
 from PLC.NodeTags import NodeTag, NodeTags
 
-from PLC.Accessors.Accessors_standard import *                  # import node accessors
+#from PLC.Accessors.Accessors_standard import *                  # import node accessors
 
 # could not define this in the class..
 # create a dict with the allowed actions for each type of node
 
 # could not define this in the class..
 # create a dict with the allowed actions for each type of node
index 92c0fc4..9800f41 100644 (file)
@@ -4,8 +4,6 @@ from PLC.Faults import *
 from PLC.Parameter import *
 from PLC.Nodes import Node, Nodes
 
 from PLC.Parameter import *
 from PLC.Nodes import Node, Nodes
 
-from PLC.Accessors.Accessors_standard import *                  # import node accessors
-
 class GetNodeFlavour(Method):
     """
     Returns detailed information on a given node's flavour, i.e. its
 class GetNodeFlavour(Method):
     """
     Returns detailed information on a given node's flavour, i.e. its
index 07a0cd0..6725f33 100644 (file)
@@ -24,7 +24,7 @@ class GetPersons(Method):
 
     accepts = [
         Auth(),
 
     accepts = [
         Auth(),
-        Mixed(Person.fields['id'],
+        Mixed(Person.fields['person_id'],
               Parameter(str,"email"),
               Filter(Person.fields)),
         Parameter([str], "List of fields to return", nullok = True)
               Parameter(str,"email"),
               Filter(Person.fields)),
         Parameter([str], "List of fields to return", nullok = True)
index 2a6e830..8167fbd 100644 (file)
@@ -3,9 +3,7 @@ from PLC.Auth import Auth
 from PLC.Faults import *
 from PLC.Parameter import *
 from PLC.Slices import Slice, Slices
 from PLC.Faults import *
 from PLC.Parameter import *
 from PLC.Slices import Slice, Slices
-
-from PLC.Accessors.Accessors_standard import *                  # import slice accessors
-from PLC.Accessors.Accessors_sliverauth import *                # import slice accessors
+from PLC.SliceTags import SliceTag, SliceTags
 
 class GetSliceFamily(Method):
     """
 
 class GetSliceFamily(Method):
     """
@@ -30,24 +28,28 @@ class GetSliceFamily(Method):
     ### system slices - at least planetflow - still rely on 'vref'
     #
     def call(self, auth, slice_id_or_name):
     ### system slices - at least planetflow - still rely on 'vref'
     #
     def call(self, auth, slice_id_or_name):
+        # default values
+        arch = self.api.config.PLC_FLAVOUR_SLICE_ARCH
+        pldistro = self.api.config.PLC_FLAVOUR_SLICE_PLDISTRO
+        fcdistro = self.api.config.PLC_FLAVOUR_SLICE_FCDISTRO
+        vref = None
         # Get slice information
         slices = Slices(self.api, [slice_id_or_name])
         if not slices:
             raise PLCInvalidArgument, "No such slice %r"%slice_id_or_name
         slice = slices[0]
         # Get slice information
         slices = Slices(self.api, [slice_id_or_name])
         if not slices:
             raise PLCInvalidArgument, "No such slice %r"%slice_id_or_name
         slice = slices[0]
-        slice_id = slice['slice_id']
-
-        arch = GetSliceArch (self.api,self.caller).call(auth,slice_id)
-        if not arch: arch = self.api.config.PLC_FLAVOUR_SLICE_ARCH
-
-        pldistro = GetSlicePldistro (self.api,self.caller).call(auth, slice_id)
-        if not pldistro: pldistro = self.api.config.PLC_FLAVOUR_SLICE_PLDISTRO
-
-        fcdistro = GetSliceFcdistro (self.api,self.caller).call(auth, slice_id)
-        if not fcdistro: fcdistro = self.api.config.PLC_FLAVOUR_SLICE_FCDISTRO
-
-        # the vref tag, if set, wins over pldistro
-        vref = GetSliceVref (self.api,self.caller).call(auth,slice_id)
+        slice_tags = SliceTags(self.api, slice['slice_tag_ids'])
+       
+        for slice_tag in slice_tags:
+            if slice_tag['tagname'] == 'arch':
+                arch = slice_tag['value']
+            elif slice_tag['tagname'] == 'pldistro':
+                pldistro = slice_tag['value']
+            elif slice_tag['tagname'] == 'fcdistro':
+                fcdistro = slice_tag['value']
+            elif slice_tag['tagname'] == 'vref':
+                vref = slice_tag['value']
 
         # omf-control'ed slivers need the omf vserver reference image
         # we used to issue SetSliceVref (self.api) (auth,slice_id,'omf')
 
         # omf-control'ed slivers need the omf vserver reference image
         # we used to issue SetSliceVref (self.api) (auth,slice_id,'omf')
index 1f65e1e..84768e5 100644 (file)
@@ -21,8 +21,6 @@ from PLC.Timestamp import Duration
 from PLC.Methods.GetSliceFamily import GetSliceFamily
 from PLC.PersonTags import PersonTag,PersonTags
 
 from PLC.Methods.GetSliceFamily import GetSliceFamily
 from PLC.PersonTags import PersonTag,PersonTags
 
-from PLC.Accessors.Accessors_standard import *
-
 # XXX used to check if slice expiration time is sane
 MAXINT =  2L**31-1
 
 # XXX used to check if slice expiration time is sane
 MAXINT =  2L**31-1
 
index 870fca7..b858ddd 100644 (file)
@@ -30,26 +30,4 @@ class UpdateKey(Method):
     returns = Parameter(int, '1 if successful')
 
     def call(self, auth, key_id, key_fields):
     returns = Parameter(int, '1 if successful')
 
     def call(self, auth, key_id, key_fields):
-        key_fields = dict(filter(can_update, key_fields.items()))
-
-        # Get key information
-        keys = Keys(self.api, [key_id])
-        if not keys:
-            raise PLCInvalidArgument, "No such key"
-        key = keys[0]
-
-        if key['peer_id'] is not None:
-            raise PLCInvalidArgument, "Not a local key"
-
-        if 'admin' not in self.caller['roles']:
-            if key['key_id'] not in self.caller['key_ids']:
-                raise PLCPermissionDenied, "Key must be associated with one of your accounts"
-
-        key.update(key_fields)
-        key.sync()
-
-        # Logging variables
-        self.event_objects = {'Key': [key['key_id']]}
-        self.message = 'key %d updated: %s' % \
-                (key['key_id'], ", ".join(key_fields.keys()))
         return 1
         return 1
index c09e10c..18207f8 100644 (file)
@@ -29,9 +29,6 @@ class UpdateNode(Method):
     roles = ['admin', 'pi', 'tech']
 
     accepted_fields = Row.accepted_fields(can_update,Node.fields)
     roles = ['admin', 'pi', 'tech']
 
     accepted_fields = Row.accepted_fields(can_update,Node.fields)
-    # xxx check the related_fields feature
-    accepted_fields.update(Node.related_fields)
-    accepted_fields.update(Node.tags)
 
     accepts = [
         Auth(),
 
     accepts = [
         Auth(),
@@ -44,22 +41,14 @@ class UpdateNode(Method):
 
     def call(self, auth, node_id_or_hostname, node_fields):
 
 
     def call(self, auth, node_id_or_hostname, node_fields):
 
-        # split provided fields
-        [native,related,tags,rejected] = Row.split_fields(node_fields,[Node.fields,Node.related_fields,Node.tags])
-
-        # type checking
-        native = Row.check_fields (native, self.accepted_fields)
-        if rejected:
-            raise PLCInvalidArgument, "Cannot update Node column(s) %r"%rejected
-
         # Authenticated function
         assert self.caller is not None
 
         # Remove admin only fields
         if 'admin' not in self.caller['roles']:
             for key in admin_only:
         # Authenticated function
         assert self.caller is not None
 
         # Remove admin only fields
         if 'admin' not in self.caller['roles']:
             for key in admin_only:
-                if native.has_key(key):
-                    del native[key]
+                if node_fields.has_key(key):
+                    del node_fields[key]
 
         # Get account information
         nodes = Nodes(self.api, [node_id_or_hostname])
 
         # Get account information
         nodes = Nodes(self.api, [node_id_or_hostname])
@@ -67,21 +56,13 @@ class UpdateNode(Method):
             raise PLCInvalidArgument, "No such node %r"%node_id_or_hostname
         node = nodes[0]
 
             raise PLCInvalidArgument, "No such node %r"%node_id_or_hostname
         node = nodes[0]
 
-        if node['peer_id'] is not None:
-            raise PLCInvalidArgument, "Not a local node %r"%node_id_or_hostname
-
         # If we are not an admin, make sure that the caller is a
         # member of the site at which the node is located.
         if 'admin' not in self.caller['roles']:
             if node['site_id'] not in self.caller['site_ids']:
                 raise PLCPermissionDenied, "Not allowed to delete nodes from specified site"
 
         # If we are not an admin, make sure that the caller is a
         # member of the site at which the node is located.
         if 'admin' not in self.caller['roles']:
             if node['site_id'] not in self.caller['site_ids']:
                 raise PLCPermissionDenied, "Not allowed to delete nodes from specified site"
 
-        # Make requested associations
-        for (k,v) in related.iteritems():
-            node.associate(auth, k,v)
-
-        node.update(native)
-        node.update_last_updated(commit=False)
+        node.update(node_fields)
         node.sync(commit=True)
 
         # if hostname was modifed make sure to update the hrn
         node.sync(commit=True)
 
         # if hostname was modifed make sure to update the hrn
@@ -112,14 +93,4 @@ class UpdateNode(Method):
                 node_tag = node_tags[0]
                 node_tag['value'] = value
                 node_tag.sync()
                 node_tag = node_tags[0]
                 node_tag['value'] = value
                 node_tag.sync()
-        # Logging variables
-        self.event_objects = {'Node': [node['node_id']]}
-        if 'hostname' in node:
-            self.message = 'Node %s updated'%node['hostname']
-        else:
-            self.message = 'Node %d updated'%node['node_id']
-        self.message += " [%s]." % (", ".join(node_fields.keys()),)
-        if 'boot_state' in node_fields.keys():
-            self.message += ' boot_state updated to %s' % node_fields['boot_state']
-
         return 1
         return 1
index 79c1900..52462b3 100644 (file)
@@ -5,11 +5,10 @@ from PLC.Persons import Person, Persons
 from PLC.Auth import Auth
 from PLC.sendmail import sendmail
 
 from PLC.Auth import Auth
 from PLC.sendmail import sendmail
 
-related_fields = Person.related_fields.keys()
 can_update = lambda (field, value): field in \
              ['first_name', 'last_name', 'title', 'email',
               'password', 'phone', 'url', 'bio', 'accepted_aup',
 can_update = lambda (field, value): field in \
              ['first_name', 'last_name', 'title', 'email',
               'password', 'phone', 'url', 'bio', 'accepted_aup',
-              'enabled'] + related_fields
+              'enabled'] 
 
 class UpdatePerson(Method):
     """
 
 class UpdatePerson(Method):
     """
@@ -24,7 +23,7 @@ class UpdatePerson(Method):
 
     roles = ['admin', 'pi', 'user', 'tech']
 
 
     roles = ['admin', 'pi', 'user', 'tech']
 
-    person_fields = dict(filter(can_update, Person.fields.items() + Person.related_fields.items()))
+    person_fields = dict(filter(can_update, Person.fields.items() ))
 
     accepts = [
         Auth(),
 
     accepts = [
         Auth(),
index 936fdae..b50890a 100644 (file)
@@ -24,7 +24,7 @@ class UpdateSite(Method):
 
     accepts = [
         Auth(),
 
     accepts = [
         Auth(),
-        Site.fields['id'],
+        Site.fields['site_id'],
         site_fields
         ]
 
         site_fields
         ]
 
@@ -45,7 +45,7 @@ class UpdateSite(Method):
         # If we are not an admin, make sure that the caller is a
         # member of the site.
         if 'admin' not in self.caller['roles']:
         # If we are not an admin, make sure that the caller is a
         # member of the site.
         if 'admin' not in self.caller['roles']:
-            if site['id'] not in self.caller['tenant_id']:
+            if site['site_id'] not in self.caller['site_id']:
                 raise PLCPermissionDenied, "Not allowed to modify specified site"
 
             # Remove admin only fields
                 raise PLCPermissionDenied, "Not allowed to modify specified site"
 
             # Remove admin only fields
index 9129ba0..5ebca66 100644 (file)
@@ -34,9 +34,6 @@ class UpdateSlice(Method):
     roles = ['admin', 'pi', 'user']
 
     accepted_fields = Row.accepted_fields(can_update, Slice.fields)
     roles = ['admin', 'pi', 'user']
 
     accepted_fields = Row.accepted_fields(can_update, Slice.fields)
-    # xxx check the related_fields feature
-    accepted_fields.update(Slice.related_fields)
-    accepted_fields.update(Slice.tags)
 
     accepts = [
         Auth(),
 
     accepts = [
         Auth(),
@@ -49,14 +46,6 @@ class UpdateSlice(Method):
 
     def call(self, auth, slice_id_or_name, slice_fields):
 
 
     def call(self, auth, slice_id_or_name, slice_fields):
 
-        # split provided fields
-        [native,related,tags,rejected] = Row.split_fields(slice_fields,[Slice.fields,Slice.related_fields,Slice.tags])
-
-        # type checking
-        native = Row.check_fields (native, self.accepted_fields)
-        if rejected:
-            raise PLCInvalidArgument, "Cannot update Slice column(s) %r"%rejected
-
         slices = Slices(self.api, [slice_id_or_name])
         if not slices:
             raise PLCInvalidArgument, "No such slice %r"%slice_id_or_name
         slices = Slices(self.api, [slice_id_or_name])
         if not slices:
             raise PLCInvalidArgument, "No such slice %r"%slice_id_or_name
@@ -110,34 +99,7 @@ class UpdateSlice(Method):
                'pi' not in self.caller['roles']:
                 raise PLCInvalidArgument, "Only admins and PIs may update max_nodes"
 
                'pi' not in self.caller['roles']:
                 raise PLCInvalidArgument, "Only admins and PIs may update max_nodes"
 
-        # Make requested associations
-        for (k,v) in related.iteritems():
-            slice.associate(auth,k,v)
-
         slice.update(slice_fields)
         slice.sync(commit=True)
 
         slice.update(slice_fields)
         slice.sync(commit=True)
 
-        for (tagname,value) in tags.iteritems():
-            # the tagtype instance is assumed to exist, just check that
-            if not TagTypes(self.api,{'tagname':tagname}):
-                raise PLCInvalidArgument,"No such TagType %s"%tagname
-            slice_tags=SliceTags(self.api,{'tagname':tagname,'slice_id':slice['slice_id']})
-            if not slice_tags:
-                AddSliceTag(self.api).__call__(auth,slice['slice_id'],tagname,value)
-            else:
-                UpdateSliceTag(self.api).__call__(auth,slice_tags[0]['slice_tag_id'],value)
-
-        self.event_objects = {'Slice': [slice['slice_id']]}
-        if 'name' in slice:
-            self.message='Slice %s updated'%slice['name']
-        else:
-            self.message='Slice %d updated'%slice['slice_id']
-        if renewing:
-            # it appears that slice['expires'] may be either an int, or a formatted string
-            try:
-                expire_date=time.strftime('%Y-%m-%d:%H:%M',time.localtime(float(slice['expires'])))
-            except:
-                expire_date=slice['expires']
-            self.message += ' renewed until %s'%expire_date
-
         return 1
         return 1
index bbe20a8..01a28d3 100644 (file)
@@ -11,7 +11,7 @@ from PLC.Debug import profile
 from PLC.Storage.AlchemyObject import AlchemyObj
 from PLC.Nodes import Node, Nodes
 
 from PLC.Storage.AlchemyObject import AlchemyObj
 from PLC.Nodes import Node, Nodes
 
-class NodeGroup(Row):
+class NodeGroup(AlchemyObj):
     """
     Representation of a row in the nodegroups table. To use, optionally
     instantiate with a dict of values. Update as you would a
     """
     Representation of a row in the nodegroups table. To use, optionally
     instantiate with a dict of values. Update as you would a
@@ -21,7 +21,7 @@ class NodeGroup(Row):
     tablename = 'nodegroups'
     join_tables = ['conf_file_nodegroup']
     fields = {
     tablename = 'nodegroups'
     join_tables = ['conf_file_nodegroup']
     fields = {
-        'nodegroup_id': Parameter(int, "Node group identifier", primary_key),
+        'nodegroup_id': Parameter(int, "Node group identifier", primary_key=True),
         'groupname': Parameter(str, "Node group name", max = 50),
         'tag_type_id': Parameter (int, "Node tag type id"),
         'value' : Parameter(str, "value that the nodegroup definition is based upon"),
         'groupname': Parameter(str, "Node group name", max = 50),
         'tag_type_id': Parameter (int, "Node tag type id"),
         'value' : Parameter(str, "value that the nodegroup definition is based upon"),
@@ -29,8 +29,6 @@ class NodeGroup(Row):
         'conf_file_ids': Parameter([int], "List of configuration files specific to this node group", joined=True),
         'node_ids' : Parameter([int], "List of node_ids that belong to this nodegroup", joined=True),
         }
         'conf_file_ids': Parameter([int], "List of configuration files specific to this node group", joined=True),
         'node_ids' : Parameter([int], "List of node_ids that belong to this nodegroup", joined=True),
         }
-    related_fields = {
-        }
 
     def validate_name(self, name):
         # Make sure name is not blank
 
     def validate_name(self, name):
         # Make sure name is not blank
index ba93906..2932d1a 100644 (file)
@@ -121,14 +121,14 @@ class Node(AlchemyObj):
         """
         Update col_name field with current time
         """
         """
         Update col_name field with current time
         """
-
         assert 'node_id' in self
         assert 'node_id' in self
-        assert self.table_name
-
-        self.api.db.do("UPDATE %s SET %s = CURRENT_TIMESTAMP " % (self.table_name, col_name) + \
-                       " where node_id = %d" % (self['node_id']) )
-        self.sync(commit)
-
+        self[col_name] = datetime.now()
+        fields = {
+            'node_id': self['node_id'],         
+            col_name: datetime.now()
+        } 
+        Node(self.api, fields).sync()
+        
     def update_last_boot(self, commit = True):
         self.update_timestamp('last_boot', commit)
     def update_last_download(self, commit = True):
     def update_last_boot(self, commit = True):
         self.update_timestamp('last_boot', commit)
     def update_last_download(self, commit = True):
index bd41936..554da90 100644 (file)
@@ -9,7 +9,7 @@ from types import StringTypes
 
 from PLC.Faults import *
 from PLC.Parameter import Parameter
 
 from PLC.Faults import *
 from PLC.Parameter import Parameter
-from PLC.Storage.AlchemyObj import AlchemyObj
+from PLC.Storage.AlchemyObject import AlchemyObj
 
 class PCUType(AlchemyObj):
     """
 
 class PCUType(AlchemyObj):
     """
index 5581a69..f6beefc 100644 (file)
@@ -16,7 +16,7 @@ class PersonTag(AlchemyObj):
     tablename = 'person_tag'
     fields = {
         'person_tag_id': Parameter(int, "Person setting identifier", primary_key=True),
     tablename = 'person_tag'
     fields = {
         'person_tag_id': Parameter(int, "Person setting identifier", primary_key=True),
-        'person_id': Person.fields['id'],
+        'person_id': Person.fields['person_id'],
         'email': Person.fields['email'],
         'tag_type_id': TagType.fields['tag_type_id'],
         'tagname': TagType.fields['tagname'],
         'email': Person.fields['email'],
         'tag_type_id': TagType.fields['tag_type_id'],
         'tagname': TagType.fields['tagname'],
index d6c3a54..fb401d3 100644 (file)
@@ -144,10 +144,6 @@ class Shell:
             if role is not None:
                 self.auth['Role'] = role
 
             if role is not None:
                 self.auth['Role'] = role
 
-        self.load_methods()
-    def load_methods(self):
-
         for method in PLC.API.PLCAPI.all_methods:
             api_function = self.api.callable(method)
 
         for method in PLC.API.PLCAPI.all_methods:
             api_function = self.api.callable(method)
 
index a79f86f..1219c2e 100644 (file)
@@ -71,11 +71,58 @@ class Slice(AlchemyObj):
         check_future = not ('is_deleted' in self and self['is_deleted'])
         return Timestamp.sql_validate( expires, check_future = check_future)
 
         check_future = not ('is_deleted' in self and self['is_deleted'])
         return Timestamp.sql_validate( expires, check_future = check_future)
 
-    #add_person = Row.add_object(Person, 'slice_person')
-    #remove_person = Row.remove_object(Person, 'slice_person')
+    def add_person(self, person_filter, role_name=None):
+        assert 'slice_id' in self
+        assert 'tenant_id' in self
+        if not role_name:
+            role_name = 'user'
+        roles = Roles(self.api, role_name)
+        if not roles:
+            raise PLCInvalidArgument, "No such role %s" % role_name
+        role = roles[0]
+        tenant = self.api.client_shell.keystone.tenants.find(id=self['tenant_id'])
+        persons = Persons(self.api, person_filter)
+        for person in persons:
+            keystone_user = self.api.client_shell.keystone.users.find(id=person['keystone_id'])
+            tenant.add_user(keystone_user, role.object)
+            slice_person = SlicePerson(self.api, {'slice_id': self['slice_id'],
+                                                  'person_id': person['person_id']})
+            slice_person.sync()
+
+    def remove_person(self, person_filter, role=None):
+        assert 'slice_id' in self
+        assert 'tenant_id' in self
+        if not role_name:
+            role_name = 'user'
+        roles = Roles(self.api, role_name)
+        if not roles:
+            raise PLCInvalidArgument, "No such role %s" % role_name
+        role = roles[0]
+        tenant = self.api.client_shell.keystone.tenants.find(id=self['tenant_id'])
+        persons = Persons(self.api, person_filter)
+        for person in persons:
+            keystone_user = self.api.client_shell.keystone.users.find(id=person['keystone_id'])
+            tenant.remove_user(keystone_user, role.object)
+            slice_person = SlicePerson(self.api, {'slice_id': self['slice_id'],
+                                                  'person_id': person['person_id']})
+            slice_person.delete()
 
 
-    #add_node = Row.add_object(Node, 'slice_node')
-    #remove_node = Row.remove_object(Node, 'slice_node')
+    def add_node(self, node_filter):
+        assert 'slice_id' in self
+        nodes = Nodes(self.api, node_filter)
+        for node in nodes:
+            slice_node = SliceNode(self.api, {'slice_id': self['slice_id'],
+                                              'node_id': node['node_id']})
+            slice_node.sync()
+    def remove_node(self, node_filter):
+        assert 'slice_id' in self
+        nodes = Nodes(self.api, node_filter)
+        for node in nodes:
+            slice_node = SliceNode(self.api, {'slice_id': self['slice_id'],
+                                              'node_id': node['node_id']})
+            slice_node.delete()
 
     #add_to_node_whitelist = Row.add_object(Node, 'node_slice_whitelist')
     #delete_from_node_whitelist = Row.remove_object(Node, 'node_slice_whitelist')
 
     #add_to_node_whitelist = Row.add_object(Node, 'node_slice_whitelist')
     #delete_from_node_whitelist = Row.remove_object(Node, 'node_slice_whitelist')
index 28c968a..8922f66 100644 (file)
@@ -25,6 +25,7 @@ Requires: python >= 2.4
 Requires: python-pycurl
 Requires: httpd
 Requires: python-gevent
 Requires: python-pycurl
 Requires: httpd
 Requires: python-gevent
+Requires: python-lxml
 # mod_wsgi will replace mod_python when we are ready
 Requires: mod_wsgi
 Requires: mod_ssl
 # mod_wsgi will replace mod_python when we are ready
 Requires: mod_wsgi
 Requires: mod_ssl