From 5d80c8d9c8016143aaf74dfd3a7e0561f7538aad Mon Sep 17 00:00:00 2001 From: Tony Mack Date: Mon, 23 Jul 2007 12:56:38 +0000 Subject: [PATCH 1/1] merge changes from HEAD --- Makefile | 3 +- ModPython.py | 2 +- PLC/Auth.py | 2 +- PLC/EventObjects.py | 32 +++++++++++++---- PLC/Events.py | 2 +- PLC/Filter.py | 56 ++++++++++++++++++++++++----- PLC/Method.py | 15 +++++--- PLC/Methods/AddNodeToPCU.py | 1 + PLC/Methods/AddSlice.py | 3 ++ PLC/Methods/DeleteNodeFromPCU.py | 1 + PLC/Methods/DeleteSliceAttribute.py | 3 -- PLC/Methods/GetNodes.py | 9 +++++ PLC/Methods/GetSlivers.py | 23 +++++++----- PLC/Methods/RefreshPeer.py | 7 +++- PLC/Methods/__init__.py | 2 +- PLC/NodeNetworks.py | 11 +++++- PLC/Nodes.py | 9 +++-- PLC/Persons.py | 13 +++++-- PLC/PostgreSQL.py | 2 +- PLC/Sessions.py | 17 +++++++-- PLC/Shell.py | 2 +- PLC/Slices.py | 7 ++-- PLCAPI.spec | 1 + doc/DocBook.py | 2 +- planetlab4.sql | 20 ++++++++++- plcsh | 2 +- refresh-peer.py | 2 +- 27 files changed, 195 insertions(+), 54 deletions(-) diff --git a/Makefile b/Makefile index 1851f23..9948225 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # Mark Huang # Copyright (C) 2005 The Trustees of Princeton University # -# $Id: Makefile,v 1.10 2006/12/15 16:20:20 mlhuang Exp $ +# $Id: Makefile,v 1.12 2007/07/02 19:28:52 tmack Exp $ # # Metafiles @@ -42,6 +42,7 @@ install: $(modules-install) --install-scripts=$(DESTDIR)/$(datadir)/plc_api \ --install-data=$(DESTDIR)/$(datadir)/plc_api install -D -m 755 php/xmlrpc/xmlrpc.so $(DESTDIR)/$(shell php-config --extension-dir)/xmlrpc.so + install -D -m 755 refresh-peer.py $(DESTDIR)/$(bindir)/refresh-peer.py $(subdirs): $(init) $(modules) diff --git a/ModPython.py b/ModPython.py index c722114..a1b2ab2 100644 --- a/ModPython.py +++ b/ModPython.py @@ -5,7 +5,7 @@ # Mark Huang # # Copyright (C) 2004-2006 The Trustees of Princeton University -# $Id$ +# $Id: ModPython.py,v 1.5 2007/02/12 18:42:49 mlhuang Exp $ # import sys diff --git a/PLC/Auth.py b/PLC/Auth.py index f62b511..83bd211 100644 --- a/PLC/Auth.py +++ b/PLC/Auth.py @@ -4,7 +4,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id$ +# $Id: Auth.py,v 1.18 2007/03/08 22:22:21 tmack Exp $ # import crypt diff --git a/PLC/EventObjects.py b/PLC/EventObjects.py index c239ca4..cbdae05 100644 --- a/PLC/EventObjects.py +++ b/PLC/EventObjects.py @@ -4,7 +4,7 @@ # Tony Mack # Copyright (C) 2006 The Trustees of Princeton University # -# $Id$ +# $Id: EventObjects.py,v 1.3 2007/05/16 18:07:02 tmack Exp $ # from PLC.Faults import * @@ -21,7 +21,7 @@ class EventObject(Row): table_name = 'event_object' primary_key = 'event_id' fields = { - 'event_object.event_id': Parameter(int, "Event identifier"), + 'event_id': Parameter(int, "Event identifier"), 'person_id': Parameter(int, "Identifier of person responsible for event, if any"), 'node_id': Parameter(int, "Identifier of node responsible for event, if any"), 'fault_code': Parameter(int, "Event fault code"), @@ -41,14 +41,34 @@ class EventObjects(Table): def __init__(self, api, event_filter = None, columns = None): Table.__init__(self, api, EventObject, columns) + + all_fields = EventObject.fields.keys() + if not columns: + columns = all_fields + else: + columns = filter(lambda column: column in all_fields, columns) + + # Since we are querying a table (not a view) ensure that timestamps + # are converted to ints in the db before being returned + timestamps = ['time'] + for col in columns: + if col in timestamps: + index = columns.index(col) + columns[index] = "CAST(date_part('epoch', events.time) AS bigint) AS time" + elif col in [EventObject.primary_key]: + index = columns.index(col) + columns[index] = EventObject.table_name+"."+EventObject.primary_key + sql = "SELECT %s FROM event_object, events WHERE True" % \ - ", ".join(self.columns) - if event_filter is not None: + ", ".join(columns) + + if event_filter is not None: if isinstance(event_filter, (list, tuple, set)): event_filter = Filter(EventObject.fields, {'event_id': event_filter}) elif isinstance(event_filter, dict): event_filter = Filter(EventObject.fields, event_filter) sql += " AND (%s) " % event_filter.sql(api) sql += " AND events.event_id = event_object.event_id " - sql += " ORDER BY %s" % EventObject.primary_key - self.selectall(sql) + sql += " ORDER BY %s" % EventObject.table_name+"."+EventObject.primary_key + + self.selectall(sql) diff --git a/PLC/Events.py b/PLC/Events.py index c66fb59..7eaaed7 100644 --- a/PLC/Events.py +++ b/PLC/Events.py @@ -4,7 +4,7 @@ # Tony Mack # Copyright (C) 2006 The Trustees of Princeton University # -# $Id$ +# $Id: Events.py,v 1.13 2007/04/11 20:29:10 tmack Exp $ # from PLC.Faults import * diff --git a/PLC/Filter.py b/PLC/Filter.py index 49990c6..c20fd9c 100644 --- a/PLC/Filter.py +++ b/PLC/Filter.py @@ -5,6 +5,8 @@ except NameError: from sets import Set set = Set +import time + from PLC.Faults import * from PLC.Parameter import Parameter, Mixed, python_type @@ -29,6 +31,13 @@ class Filter(Parameter, dict): Special forms: * a field starting with the ~ character means negation. example : { '~peer_id' : None } + * a field starting with < [ ] or > means lower than or greater than + < > uses strict comparison + [ ] is for using <= or >= instead + example : { '>time' : 1178531418 } + example : { ']event_id' : 2305 } + * a field starting with [ or ] means older than or more recent than + the associated value should be a given unix timestamp * a (string) value containing either a * or a % character is treated as a (sql) pattern; * are replaced with % that is the SQL wildcard character. @@ -55,6 +64,15 @@ class Filter(Parameter, dict): # Null filter means no filter Parameter.__init__(self, self.fields, doc = doc, nullok = True) + # this code is not used anymore + # at some point the select in the DB for event objects was done on + # the events table directly, that is stored as a timestamp, thus comparisons + # needed to be done based on SQL timestamps as well + def unix2timestamp (self,unix): + s = time.gmtime(unix) + return "TIMESTAMP'%04d-%02d-%02d %02d:%02d:%02d'" % (s.tm_year,s.tm_mon,s.tm_mday, + s.tm_hour,s.tm_min,s.tm_sec) + def sql(self, api, join_with = "AND"): """ Returns a SQL conditional that represents this filter. @@ -69,13 +87,22 @@ class Filter(Parameter, dict): assert join_with in ("AND", "OR") for field, value in self.iteritems(): - # provide for negation with a field starting with ~ - negation=False - if field[0] == '~': - negation = True - field = field[1:] + # handle negation, numeric comparisons + # simple, 1-depth only mechanism + + modifiers={'~' : False, + '<' : False, '>' : False, + '[' : False, ']' : False, + } + + for char in modifiers.keys(): + if field[0] == char: + modifiers[char]=True; + field = field[1:] + break if field not in self.fields: +# print 'current fields',self.fields raise PLCInvalidArgument, "Invalid filter field '%s'" % field if isinstance(value, (list, tuple, set)): @@ -96,12 +123,23 @@ class Filter(Parameter, dict): value = str(api.db.quote(value.replace("*", "%"))) else: operator = "=" - value = str(api.db.quote(value)) + if modifiers['<']: + operator='<' + if modifiers['>']: + operator='>' + if modifiers['[']: + operator='<=' + if modifiers[']']: + operator='>=' + else: + value = str(api.db.quote(value)) clause = "%s %s %s" % (field, operator, value) - if negation: - clause = " ( NOT %s ) "%clause - + + if modifiers['~']: + clause = " ( NOT %s ) " % (clause) + conditionals.append(clause) +# print 'sql=',(" %s " % join_with).join(conditionals) return (" %s " % join_with).join(conditionals) diff --git a/PLC/Method.py b/PLC/Method.py index 52577f5..552b703 100644 --- a/PLC/Method.py +++ b/PLC/Method.py @@ -4,7 +4,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id$ +# $Id: Method.py,v 1.27 2007/05/16 18:56:03 tmack Exp $ # import xmlrpclib @@ -98,8 +98,15 @@ class Method: return result except PLCFault, fault: - # Prepend method name to expected faults - fault.faultString = self.name + ": " + fault.faultString + + caller = "" + if isinstance(self.caller, Person): + caller = 'person_id %s' % self.caller['person_id'] + elif isinstance(self.caller, Node): + caller = 'node_id %s' % self.caller['node_id'] + + # Prepend caller and method name to expected faults + fault.faultString = caller + ": " + self.name + ": " + fault.faultString runtime = time.time() - start self.log(fault.faultCode, runtime, *args) raise fault @@ -125,7 +132,7 @@ class Method: auth_methods = ['session', 'password', 'capability', 'gpg', 'hmac','anonymous'] auth_method = args[0]['AuthMethod'] if auth_method in auth_methods: - event['auth_method'] = auth_method + event['auth_type'] = auth_method for password in 'AuthString', 'session': if args[0].has_key(password): auth = args[0].copy() diff --git a/PLC/Methods/AddNodeToPCU.py b/PLC/Methods/AddNodeToPCU.py index 2da5cd6..c0d5eff 100644 --- a/PLC/Methods/AddNodeToPCU.py +++ b/PLC/Methods/AddNodeToPCU.py @@ -3,6 +3,7 @@ from PLC.Method import Method from PLC.Parameter import Parameter, Mixed from PLC.Nodes import Node, Nodes from PLC.PCUs import PCU, PCUs +from PLC.Sites import Site, Sites from PLC.Auth import Auth class AddNodeToPCU(Method): diff --git a/PLC/Methods/AddSlice.py b/PLC/Methods/AddSlice.py index 5642519..6cc056c 100644 --- a/PLC/Methods/AddSlice.py +++ b/PLC/Methods/AddSlice.py @@ -67,6 +67,9 @@ class AddSlice(Method): len(site['slice_ids']), site['max_slices']) + if not site['enabled']: + raise PLCInvalidArgument, "Site %s is disabled can cannot create slices" % (site['name']) + slice = Slice(self.api, slice_fields) slice['creator_person_id'] = self.caller['person_id'] slice['site_id'] = site['site_id'] diff --git a/PLC/Methods/DeleteNodeFromPCU.py b/PLC/Methods/DeleteNodeFromPCU.py index d268298..8e728ef 100644 --- a/PLC/Methods/DeleteNodeFromPCU.py +++ b/PLC/Methods/DeleteNodeFromPCU.py @@ -3,6 +3,7 @@ from PLC.Method import Method from PLC.Parameter import Parameter, Mixed from PLC.Nodes import Node, Nodes from PLC.PCUs import PCU, PCUs +from PLC.Sites import Site, Sites from PLC.Auth import Auth class DeleteNodeFromPCU(Method): diff --git a/PLC/Methods/DeleteSliceAttribute.py b/PLC/Methods/DeleteSliceAttribute.py index 871e241..06a99f3 100644 --- a/PLC/Methods/DeleteSliceAttribute.py +++ b/PLC/Methods/DeleteSliceAttribute.py @@ -39,9 +39,6 @@ class DeleteSliceAttribute(Method): raise PLCInvalidArgument, "No such slice" slice = slices[0] - if slice['peer_id'] is not None: - raise PLCInvalidArgument, "Not a local slice" - assert slice_attribute['slice_attribute_id'] in slice['slice_attribute_ids'] if 'admin' not in self.caller['roles']: diff --git a/PLC/Methods/GetNodes.py b/PLC/Methods/GetNodes.py index d308a4f..38dc8f0 100644 --- a/PLC/Methods/GetNodes.py +++ b/PLC/Methods/GetNodes.py @@ -37,7 +37,16 @@ class GetNodes(Method): # Remove admin only fields if not isinstance(self.caller, Person) or \ 'admin' not in self.caller['roles']: + slice_ids = set() + if self.caller: + slice_ids.update(self.caller['slice_ids']) for node in nodes: + # if node has whitelist, make sure the user has a slice on the whitelist + if 'slice_ids_whitelist' in node and \ + node['slice_ids_whitelist'] and \ + not slice_ids.intersection(node['slice_ids_whitelist']): + nodes.remove(node) + continue for field in ['boot_nonce', 'key', 'session', 'root_person_ids']: if field in node: del node[field] diff --git a/PLC/Methods/GetSlivers.py b/PLC/Methods/GetSlivers.py index 434429d..890b65f 100644 --- a/PLC/Methods/GetSlivers.py +++ b/PLC/Methods/GetSlivers.py @@ -64,6 +64,8 @@ def get_slivers(api, slice_filter, node = None): # Per-node sliver attributes take precedence over global # slice attributes, so set them first. + # Then comes nodegroup slice attributes + # Followed by global slice attributes sliver_attributes = [] if node is not None: @@ -72,13 +74,13 @@ def get_slivers(api, slice_filter, node = None): attributes.append({'name': sliver_attribute['name'], 'value': sliver_attribute['value']}) - # set nodegroup slice attributes - for slice_attribute in filter(lambda a: a['nodegroup_id'] in node['nodegroup_ids'], slice_attributes): - # Do not set any nodegroup slice attributes for - # which there is at least one sliver attribute - # already set. - if slice_attribute['name'] not in slice_attributes: - attributes.append({'name': slice_attribute['name'], + # set nodegroup slice attributes + for slice_attribute in filter(lambda a: a['nodegroup_id'] in node['nodegroup_ids'], slice_attributes): + # Do not set any nodegroup slice attributes for + # which there is at least one sliver attribute + # already set. + if slice_attribute['name'] not in slice_attributes: + attributes.append({'name': slice_attribute['name'], 'value': slice_attribute['value']}) for slice_attribute in filter(lambda a: a['node_id'] is None, slice_attributes): @@ -202,8 +204,13 @@ class GetSlivers(Method): # Get system slices system_slice_attributes = SliceAttributes(self.api, {'name': 'system', 'value': '1'}).dict('slice_id') system_slice_ids = system_slice_attributes.keys() + + # Get nm-controller slices + controller_and_delegated_slices = Slices(self.api, {'instantiation': ['nm-controller', 'delegated']}, ['slice_id']).dict('slice_id') + controller_and_delegated_slice_ids = controller_and_delegated_slices.keys() + slice_ids = system_slice_ids + controller_and_delegated_slice_ids + node['slice_ids'] - slivers = get_slivers(self.api, system_slice_ids + node['slice_ids'], node) + slivers = get_slivers(self.api, slice_ids, node) node.update_last_contact() diff --git a/PLC/Methods/RefreshPeer.py b/PLC/Methods/RefreshPeer.py index 5332074..bf820da 100644 --- a/PLC/Methods/RefreshPeer.py +++ b/PLC/Methods/RefreshPeer.py @@ -1,7 +1,7 @@ # # Thierry Parmentelat - INRIA # -# $Id$ +# $Id: RefreshPeer.py,v 1.24 2007/06/14 16:26:23 tmack Exp $ import time @@ -228,6 +228,11 @@ class RefreshPeer(Method): # Keyed on foreign person_id old_peer_persons = Persons(self.api, {'peer_id': peer_id}, columns).dict('peer_person_id') + + # artificially attach the persons returned by GetPeerData to the new peer + # this is because validate_email needs peer_id to be correct when checking for duplicates + for person in peer_tables['Persons']: + person['peer_id']=peer_id persons_at_peer = dict([(peer_person['person_id'], peer_person) \ for peer_person in peer_tables['Persons']]) diff --git a/PLC/Methods/__init__.py b/PLC/Methods/__init__.py index f491ff9..3fc2599 100644 --- a/PLC/Methods/__init__.py +++ b/PLC/Methods/__init__.py @@ -1 +1 @@ -methods = 'AddAddressType AddAddressTypeToAddress AddBootState AddConfFile AddConfFileToNodeGroup AddConfFileToNode AddInitScript AddKeyType AddMessage AddNetworkMethod AddNetworkType AddNodeGroup AddNodeNetwork AddNode AddNodeToNodeGroup AddNodeToPCU AddPCU AddPeer AddPersonKey AddPerson AddPersonToSite AddPersonToSlice AddRole AddRoleToPerson AddSiteAddress AddSite AddSliceAttribute AddSliceAttributeType AddSliceInstantiation AddSlice AddSliceToNodes AdmAddAddressType AdmAddNodeGroup AdmAddNodeNetwork AdmAddNode AdmAddNodeToNodeGroup AdmAddPersonKey AdmAddPerson AdmAddPersonToSite AdmAddSitePowerControlUnit AdmAddSite AdmAssociateNodeToPowerControlUnitPort AdmAuthCheck AdmDeleteAddressType AdmDeleteAllPersonKeys AdmDeleteNodeGroup AdmDeleteNodeNetwork AdmDeleteNode AdmDeletePersonKeys AdmDeletePerson AdmDeleteSitePowerControlUnit AdmDeleteSite AdmDisassociatePowerControlUnitPort AdmGenerateNodeConfFile AdmGetAllAddressTypes AdmGetAllKeyTypes AdmGetAllNodeNetworks AdmGetAllRoles AdmGetNodeGroupNodes AdmGetNodeGroups AdmGetNodes AdmGetPersonKeys AdmGetPersonRoles AdmGetPersonSites AdmGetPersons AdmGetPowerControlUnitNodes AdmGetPowerControlUnits AdmGetSiteNodes AdmGetSitePersons AdmGetSitePIs AdmGetSitePowerControlUnits AdmGetSites AdmGetSiteTechContacts AdmGrantRoleToPerson AdmIsPersonInRole AdmQueryConfFile AdmQueryNode AdmQueryPerson AdmQueryPowerControlUnit AdmQuerySite AdmRebootNode AdmRemoveNodeFromNodeGroup AdmRemovePersonFromSite AdmRevokeRoleFromPerson AdmSetPersonEnabled AdmSetPersonPrimarySite AdmUpdateNodeGroup AdmUpdateNodeNetwork AdmUpdateNode AdmUpdatePerson AdmUpdateSitePowerControlUnit AdmUpdateSite AnonAdmGetNodeGroups AuthCheck BlacklistKey BootCheckAuthentication BootGetNodeDetails BootNotifyOwners BootUpdateNode DeleteAddress DeleteAddressTypeFromAddress DeleteAddressType DeleteBootState DeleteConfFileFromNodeGroup DeleteConfFileFromNode DeleteConfFile DeleteInitScript DeleteKey DeleteKeyType DeleteMessage DeleteNetworkMethod DeleteNetworkType DeleteNodeFromNodeGroup DeleteNodeFromPCU DeleteNodeGroup DeleteNodeNetwork DeleteNode DeletePCU DeletePeer DeletePersonFromSite DeletePersonFromSlice DeletePerson DeleteRoleFromPerson DeleteRole DeleteSession DeleteSite DeleteSliceAttribute DeleteSliceAttributeType DeleteSliceFromNodes DeleteSliceInstantiation DeleteSlice GetAddresses GetAddressTypes GetBootStates GetConfFiles GetEventObjects GetEvents GetInitScripts GetKeys GetKeyTypes GetMessages GetNetworkMethods GetNetworkTypes GetNodeGroups GetNodeNetworks GetNodes GetPCUs GetPeerData GetPeerName GetPeers GetPersons GetRoles GetSession GetSites GetSliceAttributes GetSliceAttributeTypes GetSliceInstantiations GetSlicesMD5 GetSlices GetSliceTicket GetSlivers NotifyPersons RebootNode RefreshPeer ResetPassword SetPersonPrimarySite SliceCreate SliceDelete SliceExtendedInfo SliceGetTicket SliceInfo SliceListNames SliceListUserSlices SliceNodesAdd SliceNodesDel SliceNodesList SliceRenew SliceTicketGet SliceUpdate SliceUserAdd SliceUserDel SliceUsersList UpdateAddress UpdateAddressType UpdateConfFile UpdateInitScript UpdateKey UpdateMessage UpdateNodeGroup UpdateNodeNetwork UpdateNode UpdatePCU UpdatePeer UpdatePerson UpdateSite UpdateSliceAttribute UpdateSliceAttributeType UpdateSlice VerifyPerson system.listMethods system.methodHelp system.methodSignature system.multicall'.split() +methods = 'AddAddressType AddAddressTypeToAddress AddBootState AddConfFile AddConfFileToNodeGroup AddConfFileToNode AddInitScript AddKeyType AddMessage AddNetworkMethod AddNetworkType AddNodeGroup AddNodeNetwork AddNode AddNodeToNodeGroup AddNodeToPCU AddPCU AddPeer AddPersonKey AddPerson AddPersonToSite AddPersonToSlice AddRole AddRoleToPerson AddSession AddSiteAddress AddSite AddSliceAttribute AddSliceAttributeType AddSliceInstantiation AddSlice AddSliceToNodes AddSliceToNodesWhitelist AdmAddAddressType AdmAddNodeGroup AdmAddNodeNetwork AdmAddNode AdmAddNodeToNodeGroup AdmAddPersonKey AdmAddPerson AdmAddPersonToSite AdmAddSitePowerControlUnit AdmAddSite AdmAssociateNodeToPowerControlUnitPort AdmAuthCheck AdmDeleteAddressType AdmDeleteAllPersonKeys AdmDeleteNodeGroup AdmDeleteNodeNetwork AdmDeleteNode AdmDeletePersonKeys AdmDeletePerson AdmDeleteSitePowerControlUnit AdmDeleteSite AdmDisassociatePowerControlUnitPort AdmGenerateNodeConfFile AdmGetAllAddressTypes AdmGetAllKeyTypes AdmGetAllNodeNetworks AdmGetAllRoles AdmGetNodeGroupNodes AdmGetNodeGroups AdmGetNodes AdmGetPersonKeys AdmGetPersonRoles AdmGetPersonSites AdmGetPersons AdmGetPowerControlUnitNodes AdmGetPowerControlUnits AdmGetSiteNodes AdmGetSitePersons AdmGetSitePIs AdmGetSitePowerControlUnits AdmGetSites AdmGetSiteTechContacts AdmGrantRoleToPerson AdmIsPersonInRole AdmQueryConfFile AdmQueryNode AdmQueryPerson AdmQueryPowerControlUnit AdmQuerySite AdmRebootNode AdmRemoveNodeFromNodeGroup AdmRemovePersonFromSite AdmRevokeRoleFromPerson AdmSetPersonEnabled AdmSetPersonPrimarySite AdmUpdateNodeGroup AdmUpdateNodeNetwork AdmUpdateNode AdmUpdatePerson AdmUpdateSitePowerControlUnit AdmUpdateSite AnonAdmGetNodeGroups AuthCheck BlacklistKey BootCheckAuthentication BootGetNodeDetails BootNotifyOwners BootUpdateNode DeleteAddress DeleteAddressTypeFromAddress DeleteAddressType DeleteBootState DeleteConfFileFromNodeGroup DeleteConfFileFromNode DeleteConfFile DeleteInitScript DeleteKey DeleteKeyType DeleteMessage DeleteNetworkMethod DeleteNetworkType DeleteNodeFromNodeGroup DeleteNodeFromPCU DeleteNodeGroup DeleteNodeNetwork DeleteNode DeletePCU DeletePeer DeletePersonFromSite DeletePersonFromSlice DeletePerson DeleteRoleFromPerson DeleteRole DeleteSession DeleteSite DeleteSliceAttribute DeleteSliceAttributeType DeleteSliceFromNodes DeleteSliceFromNodesWhitelist DeleteSliceInstantiation DeleteSlice GenerateNodeConfFile GetAddresses GetAddressTypes GetBootStates GetConfFiles GetEventObjects GetEvents GetInitScripts GetKeys GetKeyTypes GetMessages GetNetworkMethods GetNetworkTypes GetNodeGroups GetNodeNetworks GetNodes GetPCUs GetPeerData GetPeerName GetPeers GetPersons GetRoles GetSession GetSessions GetSites GetSliceAttributes GetSliceAttributeTypes GetSliceInstantiations GetSlicesMD5 GetSlices GetSliceTicket GetSlivers NotifyPersons RebootNode RefreshPeer ResetPassword SetPersonPrimarySite SliceCreate SliceDelete SliceExtendedInfo SliceGetTicket SliceInfo SliceListNames SliceListUserSlices SliceNodesAdd SliceNodesDel SliceNodesList SliceRenew SliceTicketGet SliceUpdate SliceUserAdd SliceUserDel SliceUsersList UpdateAddress UpdateAddressType UpdateConfFile UpdateInitScript UpdateKey UpdateMessage UpdateNodeGroup UpdateNodeNetwork UpdateNode UpdatePCU UpdatePeer UpdatePerson UpdateSite UpdateSliceAttribute UpdateSliceAttributeType UpdateSlice VerifyPerson system.listMethods system.methodHelp system.methodSignature system.multicall'.split() diff --git a/PLC/NodeNetworks.py b/PLC/NodeNetworks.py index 8733f8d..a643f08 100644 --- a/PLC/NodeNetworks.py +++ b/PLC/NodeNetworks.py @@ -4,7 +4,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: NodeNetworks.py,v 1.15 2006/11/09 19:43:55 mlhuang Exp $ +# $Id: NodeNetworks.py,v 1.17 2007/05/11 20:22:55 tmack Exp $ # from types import StringTypes @@ -109,6 +109,15 @@ class NodeNetwork(Row): validate_dns1 = validate_ip validate_dns2 = validate_ip + def validate_bwlimit(self, bwlimit): + if not bwlimit: + return bwlimit + + if bwlimit < 500000: + raise PLCInvalidArgument, 'Minimum bw is 500 kbs' + + return bwlimit + def validate_hostname(self, hostname): # Optional if not hostname: diff --git a/PLC/Nodes.py b/PLC/Nodes.py index 7954627..4596870 100644 --- a/PLC/Nodes.py +++ b/PLC/Nodes.py @@ -4,7 +4,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id$ +# $Id: Nodes.py,v 1.34 2007/07/12 17:55:02 tmack Exp $ # from types import StringTypes @@ -17,6 +17,7 @@ from PLC.Debug import profile from PLC.Table import Row, Table from PLC.NodeNetworks import NodeNetwork, NodeNetworks from PLC.BootStates import BootStates +#from PLC.Slices import Slice, Slices def valid_hostname(hostname): # 1. Each part begins and ends with a letter or number. @@ -38,7 +39,7 @@ class Node(Row): table_name = 'nodes' primary_key = 'node_id' - join_tables = ['nodegroup_node', 'conf_file_node', 'nodenetworks', 'pcu_node', 'slice_node', 'slice_attribute', 'node_session', 'peer_node'] + join_tables = ['nodegroup_node', 'conf_file_node', 'nodenetworks', 'pcu_node', 'slice_node', 'slice_attribute', 'node_session', 'peer_node', 'node_slice_whitelist'] fields = { 'node_id': Parameter(int, "Node identifier"), 'hostname': Parameter(str, "Fully qualified hostname", max = 255), @@ -58,6 +59,7 @@ class Node(Row): 'conf_file_ids': Parameter([int], "List of configuration files specific to this node"), # 'root_person_ids': Parameter([int], "(Admin only) List of people who have root access to this node"), 'slice_ids': Parameter([int], "List of slices on this node"), + 'slice_ids_whitelist': Parameter([int], "List of slices allowed on this node"), 'pcu_ids': Parameter([int], "List of PCUs that control this node"), 'ports': Parameter([int], "List of PCU ports that this node is connected to"), 'peer_id': Parameter(int, "Peer to which this node belongs", nullok = True), @@ -95,6 +97,7 @@ class Node(Row): validate_date_created = Row.validate_timestamp validate_last_updated = Row.validate_timestamp + validate_last_contact = Row.validate_timestamp def update_last_contact(self, commit = True): """ @@ -107,7 +110,7 @@ class Node(Row): self.api.db.do("UPDATE %s SET last_contact = CURRENT_TIMESTAMP " % (self.table_name) + \ " where node_id = %d" % ( self['node_id']) ) self.sync(commit) - + def delete(self, commit = True): """ Delete existing node. diff --git a/PLC/Persons.py b/PLC/Persons.py index 7a2e635..8e483b3 100644 --- a/PLC/Persons.py +++ b/PLC/Persons.py @@ -4,7 +4,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id$ +# $Id: Persons.py,v 1.37 2007/06/14 16:26:01 tmack Exp $ # from types import StringTypes @@ -100,8 +100,15 @@ class Person(Row): if len(domain) < 2: raise invalid_email - conflicts = Persons(self.api, [email]) - for person in conflicts: + # check only against users on the same peer + if 'peer_id' in self: + namespace_peer_id = self['peer_id'] + else: + namespace_peer_id = None + + conflicts = Persons(self.api, {'email':email,'peer_id':namespace_peer_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" diff --git a/PLC/PostgreSQL.py b/PLC/PostgreSQL.py index 597077a..9100ce1 100644 --- a/PLC/PostgreSQL.py +++ b/PLC/PostgreSQL.py @@ -5,7 +5,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id$ +# $Id: PostgreSQL.py,v 1.15 2007/02/12 18:41:27 mlhuang Exp $ # import psycopg2 diff --git a/PLC/Sessions.py b/PLC/Sessions.py index 3c1543e..b470c96 100644 --- a/PLC/Sessions.py +++ b/PLC/Sessions.py @@ -1,9 +1,12 @@ +from types import StringTypes import random import base64 import time 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.Persons import Person, Persons from PLC.Nodes import Node, Nodes @@ -61,14 +64,22 @@ class Sessions(Table): Representation of row(s) from the session table in the database. """ - def __init__(self, api, session_ids = None, expires = int(time.time())): + def __init__(self, api, session_filter = None, expires = int(time.time())): Table.__init__(self, api, Session) sql = "SELECT %s FROM view_sessions WHERE True" % \ ", ".join(Session.fields) - if session_ids: - sql += " AND session_id IN (%s)" % ", ".join(map(api.db.quote, session_ids)) + if session_filter is not None: + if isinstance(session_filter, (list, tuple, set)): + # Separate the list into integers and strings + ints = filter(lambda x: isinstance(x, (int, long)), session_filter) + strs = filter(lambda x: isinstance(x, StringTypes), session_filter) + session_filter = Filter(Session.fields, {'person_id': ints, 'session_id': strs}) + sql += " AND (%s)" % session_filter.sql(api, "OR") + elif isinstance(session_filter, dict): + session_filter = Filter(Session.fields, session_filter) + sql += " AND (%s)" % session_filter.sql(api, "AND") if expires is not None: if expires >= 0: diff --git a/PLC/Shell.py b/PLC/Shell.py index 6e4a77b..6782fff 100644 --- a/PLC/Shell.py +++ b/PLC/Shell.py @@ -5,7 +5,7 @@ # Mark Huang # Copyright (C) 2005 The Trustees of Princeton University # -# $Id$ +# $Id: Shell.py,v 1.5 2007/02/08 21:49:24 mlhuang Exp $ # import os diff --git a/PLC/Slices.py b/PLC/Slices.py index d3b6f78..d8962c4 100644 --- a/PLC/Slices.py +++ b/PLC/Slices.py @@ -8,7 +8,7 @@ from PLC.Filter import Filter from PLC.Debug import profile from PLC.Table import Row, Table from PLC.SliceInstantiations import SliceInstantiation, SliceInstantiations -from PLC.Nodes import Node, Nodes +from PLC.Nodes import Node from PLC.Persons import Person, Persons class Slice(Row): @@ -21,7 +21,7 @@ class Slice(Row): table_name = 'slices' primary_key = 'slice_id' - join_tables = ['slice_node', 'slice_person', 'slice_attribute', 'peer_slice'] + join_tables = ['slice_node', 'slice_person', 'slice_attribute', 'peer_slice', 'node_slice_whitelist'] fields = { 'slice_id': Parameter(int, "Slice identifier"), 'site_id': Parameter(int, "Identifier of the site to which this slice belongs"), @@ -94,6 +94,9 @@ class Slice(Row): add_node = Row.add_object(Node, 'slice_node') remove_node = Row.remove_object(Node, 'slice_node') + add_to_node_whitelist = Row.add_object(Node, 'node_slice_whitelist') + delete_from_node_whitelist = Row.remove_object(Node, 'node_slice_whitelist') + def sync(self, commit = True): """ Add or update a slice. diff --git a/PLCAPI.spec b/PLCAPI.spec index 0b8f86c..6701045 100644 --- a/PLCAPI.spec +++ b/PLCAPI.spec @@ -74,6 +74,7 @@ rm -rf $RPM_BUILD_ROOT %{_bindir}/plcsh %{php_extension_dir}/xmlrpc.so %{_sysconfdir}/php.d/xmlrpc.ini +%{_bindir}/refresh-peer.py %changelog * Fri Oct 27 2006 Mark Huang - diff --git a/doc/DocBook.py b/doc/DocBook.py index 91f0ff4..7867e47 100755 --- a/doc/DocBook.py +++ b/doc/DocBook.py @@ -6,7 +6,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id$ +# $Id: DocBook.py,v 1.4 2007/02/19 18:02:39 mlhuang Exp $ # import xml.dom.minidom diff --git a/planetlab4.sql b/planetlab4.sql index f14d403..3bd82fa 100644 --- a/planetlab4.sql +++ b/planetlab4.sql @@ -9,7 +9,7 @@ -- -- Copyright (C) 2006 The Trustees of Princeton University -- --- $Id$ +-- $Id: planetlab4.sql,v 1.79 2007/07/12 17:48:19 tmack Exp $ -- SET client_encoding = 'UNICODE'; @@ -295,6 +295,22 @@ array_accum(node_id) AS node_ids FROM nodes GROUP BY site_id; +-- slice whitelist on nodes +CREATE TABLE node_slice_whitelist ( + node_id integer REFERENCES nodes NOT NULL, -- Node id of whitelist + slice_id integer REFERENCES slices NOT NULL, -- Slice id thats allowd on this node + PRIMARY KEY (node_id, slice_id) +) WITH OIDS; +CREATE INDEX node_slice_whitelist_node_id_idx ON node_slice_whitelist (node_id); +CREATE INDEX node_slice_whitelist_slice_id_idx ON node_slice_whitelist (slice_id); + +-- Slices on each node +CREATE VIEW node_slices_whitelist AS +SELECT node_id, +array_accum(slice_id) AS slice_ids_whitelist +FROM node_slice_whitelist +GROUP BY node_id; + -------------------------------------------------------------------------------- -- Node groups -------------------------------------------------------------------------------- @@ -509,6 +525,7 @@ CREATE TABLE slice_instantiations ( INSERT INTO slice_instantiations (instantiation) VALUES ('not-instantiated'); -- Placeholder slice INSERT INTO slice_instantiations (instantiation) VALUES ('plc-instantiated'); -- Instantiated by Node Manager INSERT INTO slice_instantiations (instantiation) VALUES ('delegated'); -- Manually instantiated +INSERT INTO slice_instantiations (instantiation) VALUES ('nm-controller'); -- NM Controller -- Slices CREATE TABLE slices ( @@ -881,6 +898,7 @@ peer_node.peer_node_id, COALESCE((SELECT nodenetwork_ids FROM node_nodenetworks WHERE node_nodenetworks.node_id = nodes.node_id), '{}') AS nodenetwork_ids, COALESCE((SELECT nodegroup_ids FROM node_nodegroups WHERE node_nodegroups.node_id = nodes.node_id), '{}') AS nodegroup_ids, COALESCE((SELECT slice_ids FROM node_slices WHERE node_slices.node_id = nodes.node_id), '{}') AS slice_ids, +COALESCE((SELECT slice_ids_whitelist FROM node_slices_whitelist WHERE node_slices_whitelist.node_id = nodes.node_id), '{}') AS slice_ids_whitelist, COALESCE((SELECT pcu_ids FROM node_pcus WHERE node_pcus.node_id = nodes.node_id), '{}') AS pcu_ids, COALESCE((SELECT ports FROM node_pcus WHERE node_pcus.node_id = nodes.node_id), '{}') AS ports, COALESCE((SELECT conf_file_ids FROM node_conf_files WHERE node_conf_files.node_id = nodes.node_id), '{}') AS conf_file_ids, diff --git a/plcsh b/plcsh index 10944b0..54fc0b9 100755 --- a/plcsh +++ b/plcsh @@ -5,7 +5,7 @@ # Mark Huang # Copyright (C) 2005 The Trustees of Princeton University # -# $Id$ +# $Id: plcsh,v 1.6 2007/02/08 21:49:41 mlhuang Exp $ # import os diff --git a/refresh-peer.py b/refresh-peer.py index ae38841..484d257 100644 --- a/refresh-peer.py +++ b/refresh-peer.py @@ -1,5 +1,5 @@ #!/usr/bin/env plcsh -# $Id: refresh-peer.py 154 2007-03-28 14:15:55Z thierry $ +# $Id: refresh-peer.py,v 1.1 2007/07/02 19:27:43 tmack Exp $ import sys,os,time -- 2.43.0