From: Tony Mack Date: Thu, 11 Oct 2012 18:09:06 +0000 (-0400) Subject: bug fixes X-Git-Url: http://git.onelab.eu/?p=plcapi.git;a=commitdiff_plain;h=567b2eb0fcdf0d9c5e8024afdaaf30ea95bba0cf bug fixes --- diff --git a/PLC/API.py b/PLC/API.py index 16d3a61..cd0520b 100644 --- a/PLC/API.py +++ b/PLC/API.py @@ -171,7 +171,8 @@ class PLCAPI: 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): """ diff --git a/PLC/GPG.py b/PLC/GPG.py index ffecff0..f239741 100644 --- a/PLC/GPG.py +++ b/PLC/GPG.py @@ -14,7 +14,8 @@ import shutil 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 @@ -28,17 +29,10 @@ def canonicalize(args, methodname = None, methodresponse = False): """ 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. diff --git a/PLC/InterfaceTags.py b/PLC/InterfaceTags.py index 4ed6e96..3c0644e 100644 --- a/PLC/InterfaceTags.py +++ b/PLC/InterfaceTags.py @@ -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): - 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 diff --git a/PLC/Keys.py b/PLC/Keys.py index 6f82838..c174470 100644 --- a/PLC/Keys.py +++ b/PLC/Keys.py @@ -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.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 @@ -16,24 +16,30 @@ class Key(NovaObject): """ tablename = 'keys' - join_tables = ['person_key', 'peer_key'] 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): - 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): @@ -79,26 +85,9 @@ class Key(NovaObject): 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. diff --git a/PLC/Methods/AddNode.py b/PLC/Methods/AddNode.py index 3a5ce90..830444e 100644 --- a/PLC/Methods/AddNode.py +++ b/PLC/Methods/AddNode.py @@ -10,7 +10,8 @@ from PLC.NodeTags import NodeTags, NodeTag 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): """ @@ -25,8 +26,7 @@ class AddNode(Method): 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(), @@ -39,13 +39,6 @@ class AddNode(Method): 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: @@ -65,13 +58,15 @@ class AddNode(Method): 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'] + tags={} 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() - 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'] diff --git a/PLC/Methods/AddNodeGroup.py b/PLC/Methods/AddNodeGroup.py index a24fa8e..505327f 100644 --- a/PLC/Methods/AddNodeGroup.py +++ b/PLC/Methods/AddNodeGroup.py @@ -7,7 +7,7 @@ from PLC.NodeGroups import NodeGroup, NodeGroups 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): """ diff --git a/PLC/Methods/AddPCUType.py b/PLC/Methods/AddPCUType.py index 2c8fbe5..1037883 100644 --- a/PLC/Methods/AddPCUType.py +++ b/PLC/Methods/AddPCUType.py @@ -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() - self.event_object = {'PCUType': [pcu_type['pcu_type_id']]} return pcu_type['pcu_type_id'] diff --git a/PLC/Methods/AddRoleToPerson.py b/PLC/Methods/AddRoleToPerson.py index 1e47033..3fc1df3 100644 --- a/PLC/Methods/AddRoleToPerson.py +++ b/PLC/Methods/AddRoleToPerson.py @@ -19,7 +19,7 @@ class AddRoleToPerson(Method): accepts = [ Auth(), - Mixed(Role.fields['role_id'], + Mixed(Role.fields['id'], 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] - if person['peer_id'] is not None: - raise PLCInvalidArgument, "Not a local account" - # 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) - 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 diff --git a/PLC/Methods/BootNotifyOwners.py b/PLC/Methods/BootNotifyOwners.py index 7458b9d..13799f7 100644 --- a/PLC/Methods/BootNotifyOwners.py +++ b/PLC/Methods/BootNotifyOwners.py @@ -1,6 +1,6 @@ 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 diff --git a/PLC/Methods/DeleteRoleFromTagType.py b/PLC/Methods/DeleteRoleFromTagType.py index cdce6fa..db009d2 100644 --- a/PLC/Methods/DeleteRoleFromTagType.py +++ b/PLC/Methods/DeleteRoleFromTagType.py @@ -19,7 +19,7 @@ class DeleteRoleFromTagType(Method): accepts = [ Auth(), - Mixed(Role.fields['role_id'], + Mixed(Role.fields['id'], Role.fields['name']), Mixed(TagType.fields['tag_type_id'], TagType.fields['tagname']), diff --git a/PLC/Methods/GetBootMedium.py b/PLC/Methods/GetBootMedium.py index 7225b12..b1380db 100644 --- a/PLC/Methods/GetBootMedium.py +++ b/PLC/Methods/GetBootMedium.py @@ -14,7 +14,7 @@ from PLC.Interfaces import Interface, Interfaces 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 diff --git a/PLC/Methods/GetNodeFlavour.py b/PLC/Methods/GetNodeFlavour.py index 92c0fc4..9800f41 100644 --- a/PLC/Methods/GetNodeFlavour.py +++ b/PLC/Methods/GetNodeFlavour.py @@ -4,8 +4,6 @@ from PLC.Faults import * 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 diff --git a/PLC/Methods/GetPersons.py b/PLC/Methods/GetPersons.py index 07a0cd0..6725f33 100644 --- a/PLC/Methods/GetPersons.py +++ b/PLC/Methods/GetPersons.py @@ -24,7 +24,7 @@ class GetPersons(Method): 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) diff --git a/PLC/Methods/GetSliceFamily.py b/PLC/Methods/GetSliceFamily.py index 2a6e830..8167fbd 100644 --- a/PLC/Methods/GetSliceFamily.py +++ b/PLC/Methods/GetSliceFamily.py @@ -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.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): """ @@ -30,24 +28,28 @@ class GetSliceFamily(Method): ### 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] - 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') diff --git a/PLC/Methods/GetSlivers.py b/PLC/Methods/GetSlivers.py index 1f65e1e..84768e5 100644 --- a/PLC/Methods/GetSlivers.py +++ b/PLC/Methods/GetSlivers.py @@ -21,8 +21,6 @@ from PLC.Timestamp import Duration 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 diff --git a/PLC/Methods/UpdateKey.py b/PLC/Methods/UpdateKey.py index 870fca7..b858ddd 100644 --- a/PLC/Methods/UpdateKey.py +++ b/PLC/Methods/UpdateKey.py @@ -30,26 +30,4 @@ class UpdateKey(Method): 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 diff --git a/PLC/Methods/UpdateNode.py b/PLC/Methods/UpdateNode.py index c09e10c..18207f8 100644 --- a/PLC/Methods/UpdateNode.py +++ b/PLC/Methods/UpdateNode.py @@ -29,9 +29,6 @@ class UpdateNode(Method): 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(), @@ -44,22 +41,14 @@ class UpdateNode(Method): 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: - 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]) @@ -67,21 +56,13 @@ class UpdateNode(Method): 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" - # 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 @@ -112,14 +93,4 @@ class UpdateNode(Method): 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 diff --git a/PLC/Methods/UpdatePerson.py b/PLC/Methods/UpdatePerson.py index 79c1900..52462b3 100644 --- a/PLC/Methods/UpdatePerson.py +++ b/PLC/Methods/UpdatePerson.py @@ -5,11 +5,10 @@ from PLC.Persons import Person, Persons 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', - 'enabled'] + related_fields + 'enabled'] class UpdatePerson(Method): """ @@ -24,7 +23,7 @@ class UpdatePerson(Method): 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(), diff --git a/PLC/Methods/UpdateSite.py b/PLC/Methods/UpdateSite.py index 936fdae..b50890a 100644 --- a/PLC/Methods/UpdateSite.py +++ b/PLC/Methods/UpdateSite.py @@ -24,7 +24,7 @@ class UpdateSite(Method): accepts = [ Auth(), - Site.fields['id'], + Site.fields['site_id'], 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 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 diff --git a/PLC/Methods/UpdateSlice.py b/PLC/Methods/UpdateSlice.py index 9129ba0..5ebca66 100644 --- a/PLC/Methods/UpdateSlice.py +++ b/PLC/Methods/UpdateSlice.py @@ -34,9 +34,6 @@ class UpdateSlice(Method): 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(), @@ -49,14 +46,6 @@ class UpdateSlice(Method): 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 @@ -110,34 +99,7 @@ class UpdateSlice(Method): '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) - 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 diff --git a/PLC/NodeGroups.py b/PLC/NodeGroups.py index bbe20a8..01a28d3 100644 --- a/PLC/NodeGroups.py +++ b/PLC/NodeGroups.py @@ -11,7 +11,7 @@ from PLC.Debug import profile 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 @@ -21,7 +21,7 @@ class NodeGroup(Row): 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"), @@ -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), } - related_fields = { - } def validate_name(self, name): # Make sure name is not blank diff --git a/PLC/Nodes.py b/PLC/Nodes.py index ba93906..2932d1a 100644 --- a/PLC/Nodes.py +++ b/PLC/Nodes.py @@ -121,14 +121,14 @@ class Node(AlchemyObj): """ Update col_name field with current time """ - 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): diff --git a/PLC/PCUTypes.py b/PLC/PCUTypes.py index bd41936..554da90 100644 --- a/PLC/PCUTypes.py +++ b/PLC/PCUTypes.py @@ -9,7 +9,7 @@ from types import StringTypes from PLC.Faults import * from PLC.Parameter import Parameter -from PLC.Storage.AlchemyObj import AlchemyObj +from PLC.Storage.AlchemyObject import AlchemyObj class PCUType(AlchemyObj): """ diff --git a/PLC/PersonTags.py b/PLC/PersonTags.py index 5581a69..f6beefc 100644 --- a/PLC/PersonTags.py +++ b/PLC/PersonTags.py @@ -16,7 +16,7 @@ class PersonTag(AlchemyObj): 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'], diff --git a/PLC/Shell.py b/PLC/Shell.py index d6c3a54..fb401d3 100644 --- a/PLC/Shell.py +++ b/PLC/Shell.py @@ -144,10 +144,6 @@ class Shell: 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) diff --git a/PLC/Slices.py b/PLC/Slices.py index a79f86f..1219c2e 100644 --- a/PLC/Slices.py +++ b/PLC/Slices.py @@ -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) - #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') diff --git a/PLCAPI.spec b/PLCAPI.spec index 28c968a..8922f66 100644 --- a/PLCAPI.spec +++ b/PLCAPI.spec @@ -25,6 +25,7 @@ Requires: python >= 2.4 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