From a0e131a2893c75df786c94997370b01cb623dee0 Mon Sep 17 00:00:00 2001 From: Tony Mack Date: Tue, 13 Nov 2007 22:56:38 +0000 Subject: [PATCH] merge from trunk --- PLC/API.py | 2 +- PLC/AddressTypes.py | 6 +- PLC/Addresses.py | 2 +- PLC/Auth.py | 2 +- PLC/Boot.py | 2 +- PLC/BootStates.py | 2 +- PLC/ConfFiles.py | 4 +- PLC/Config.py | 2 +- PLC/EventObjects.py | 11 ++- PLC/Events.py | 7 +- PLC/Faults.py | 2 +- PLC/Filter.py | 170 ++++++++++++++++++++++----------- PLC/GPG.py | 2 +- PLC/InitScripts.py | 4 +- PLC/KeyTypes.py | 2 +- PLC/Keys.py | 2 +- PLC/Messages.py | 6 +- PLC/Method.py | 2 +- PLC/NetworkMethods.py | 2 +- PLC/NetworkTypes.py | 2 +- PLC/NodeGroups.py | 70 ++++++++++++-- PLC/NodeNetworkSettingTypes.py | 8 +- PLC/NodeNetworkSettings.py | 4 +- PLC/NodeNetworks.py | 4 +- PLC/Nodes.py | 160 +++++++++++++++++++++++++++++-- PLC/PCUProtocolTypes.py | 75 +++++++++++++++ PLC/PCUTypes.py | 104 ++++++++++++++++++++ PLC/PCUs.py | 4 +- PLC/Parameter.py | 2 +- PLC/Peers.py | 4 +- PLC/Persons.py | 156 ++++++++++++++++++++++++++++-- PLC/PostgreSQL.py | 2 +- PLC/PyCurl.py | 2 +- PLC/Roles.py | 6 +- PLC/Sessions.py | 4 +- PLC/Shell.py | 2 +- PLC/Sites.py | 87 +++++++++++++++-- PLC/SliceAttributeTypes.py | 4 +- PLC/SliceAttributes.py | 2 +- PLC/SliceInstantiations.py | 2 +- PLC/Slices.py | 141 +++++++++++++++++++++++++-- PLC/Table.py | 29 ++++++ PLC/Test.py | 2 +- PLC/__init__.py | 18 ++-- 44 files changed, 970 insertions(+), 156 deletions(-) create mode 100644 PLC/PCUProtocolTypes.py create mode 100644 PLC/PCUTypes.py diff --git a/PLC/API.py b/PLC/API.py index 5c068485..5c4cb9d5 100644 --- a/PLC/API.py +++ b/PLC/API.py @@ -5,7 +5,7 @@ # Mark Huang # # Copyright (C) 2004-2006 The Trustees of Princeton University -# $Id: API.py,v 1.8 2007/01/05 16:09:09 tmack Exp $ +# $Id: API.py 5574 2007-10-25 20:33:17Z thierry $ # import sys diff --git a/PLC/AddressTypes.py b/PLC/AddressTypes.py index 19f9b168..7156c00b 100644 --- a/PLC/AddressTypes.py +++ b/PLC/AddressTypes.py @@ -4,7 +4,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: AddressTypes.py,v 1.8 2006/11/09 03:07:42 mlhuang Exp $ +# $Id: AddressTypes.py 5574 2007-10-25 20:33:17Z thierry $ # from types import StringTypes @@ -58,9 +58,9 @@ class AddressTypes(Table): ints = filter(lambda x: isinstance(x, (int, long)), address_type_filter) strs = filter(lambda x: isinstance(x, StringTypes), address_type_filter) address_type_filter = Filter(AddressType.fields, {'address_type_id': ints, 'name': strs}) - sql += " AND (%s)" % address_type_filter.sql(api, "OR") + sql += " AND (%s) %s" % address_type_filter.sql(api, "OR") elif isinstance(address_type_filter, dict): address_type_filter = Filter(AddressType.fields, address_type_filter) - sql += " AND (%s)" % address_type_filter.sql(api, "AND") + sql += " AND (%s) %s" % address_type_filter.sql(api, "AND") self.selectall(sql) diff --git a/PLC/Addresses.py b/PLC/Addresses.py index 62f9e3bd..36c0d1dc 100644 --- a/PLC/Addresses.py +++ b/PLC/Addresses.py @@ -94,6 +94,6 @@ class Addresses(Table): address_filter = Filter(Address.fields, {'address_id': address_filter}) elif isinstance(address_filter, dict): address_filter = Filter(Address.fields, address_filter) - sql += " AND (%s)" % address_filter.sql(api) + sql += " AND (%s) %s" % address_filter.sql(api) self.selectall(sql) diff --git a/PLC/Auth.py b/PLC/Auth.py index 83bd2115..498acc56 100644 --- a/PLC/Auth.py +++ b/PLC/Auth.py @@ -4,7 +4,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: Auth.py,v 1.18 2007/03/08 22:22:21 tmack Exp $ +# $Id: Auth.py 5574 2007-10-25 20:33:17Z thierry $ # import crypt diff --git a/PLC/Boot.py b/PLC/Boot.py index cd3a7389..00a33caa 100644 --- a/PLC/Boot.py +++ b/PLC/Boot.py @@ -4,7 +4,7 @@ # Mark Huang # Copyright (C) 2007 The Trustees of Princeton University # -# $Id$ +# $Id: Boot.py 5574 2007-10-25 20:33:17Z thierry $ # from PLC.Faults import * diff --git a/PLC/BootStates.py b/PLC/BootStates.py index 42a5214d..014b61a8 100644 --- a/PLC/BootStates.py +++ b/PLC/BootStates.py @@ -4,7 +4,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: BootStates.py,v 1.6 2006/10/24 20:02:22 mlhuang Exp $ +# $Id: BootStates.py 5574 2007-10-25 20:33:17Z thierry $ # from PLC.Faults import * diff --git a/PLC/ConfFiles.py b/PLC/ConfFiles.py index 78853df2..f15a574a 100644 --- a/PLC/ConfFiles.py +++ b/PLC/ConfFiles.py @@ -4,7 +4,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: ConfFiles.py,v 1.9 2006/11/09 03:07:42 mlhuang Exp $ +# $Id: ConfFiles.py 5574 2007-10-25 20:33:17Z thierry $ # from PLC.Faults import * @@ -150,6 +150,6 @@ class ConfFiles(Table): conf_file_filter = Filter(ConfFile.fields, {'conf_file_id': conf_file_filter}) elif isinstance(conf_file_filter, dict): conf_file_filter = Filter(ConfFile.fields, conf_file_filter) - sql += " AND (%s)" % conf_file_filter.sql(api) + sql += " AND (%s) %s" % conf_file_filter.sql(api) self.selectall(sql) diff --git a/PLC/Config.py b/PLC/Config.py index 97233f0c..693ba221 100644 --- a/PLC/Config.py +++ b/PLC/Config.py @@ -6,7 +6,7 @@ # Mark Huang # Copyright (C) 2004-2006 The Trustees of Princeton University # -# $Id: Config.py,v 1.2 2006/09/06 19:15:59 mlhuang Exp $ +# $Id: Config.py 5574 2007-10-25 20:33:17Z thierry $ # import os diff --git a/PLC/EventObjects.py b/PLC/EventObjects.py index 9ba241ab..52b44c72 100644 --- a/PLC/EventObjects.py +++ b/PLC/EventObjects.py @@ -4,7 +4,7 @@ # Tony Mack # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: EventObjects.py,v 1.4 2007/09/12 17:52:27 tmack Exp $ +# $Id: EventObjects.py 5574 2007-10-25 20:33:17Z thierry $ # from PLC.Faults import * @@ -48,15 +48,16 @@ class EventObjects(Table): if event_filter is not None: if isinstance(event_filter, (list, tuple, set)): event_filter = Filter(EventObject.fields, {'event_id': event_filter}) - sql += " AND (%s)" % event_filter.sql(api, "OR") + sql += " AND (%s) %s" % event_filter.sql(api, "OR") elif isinstance(event_filter, dict): event_filter = Filter(EventObject.fields, event_filter) - sql += " AND (%s)" % event_filter.sql(api, "AND") + sql += " AND (%s) %s" % event_filter.sql(api, "AND") elif isinstance (event_filter, int): event_filter = Filter(EventObject.fields, {'event_id':[event_filter]}) - sql += " AND (%s)" % event_filter.sql(api, "AND") + sql += " AND (%s) %s" % event_filter.sql(api, "AND") else: raise PLCInvalidArgument, "Wrong event object filter %r"%event_filter - sql += " ORDER BY %s" % EventObject.primary_key +# with new filtering, caller needs to set this explicitly +# sql += " ORDER BY %s" % EventObject.primary_key self.selectall(sql) diff --git a/PLC/Events.py b/PLC/Events.py index 7eaaed77..0d319cf2 100644 --- a/PLC/Events.py +++ b/PLC/Events.py @@ -4,7 +4,7 @@ # Tony Mack # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: Events.py,v 1.13 2007/04/11 20:29:10 tmack Exp $ +# $Id: Events.py 5574 2007-10-25 20:33:17Z thierry $ # from PLC.Faults import * @@ -73,6 +73,7 @@ class Events(Table): event_filter = Filter(Event.fields, {'event_id': event_filter}) elif isinstance(event_filter, dict): event_filter = Filter(Event.fields, event_filter) - sql += " AND (%s)" % event_filter.sql(api) - sql += " ORDER BY %s" % Event.primary_key + sql += " AND (%s) %s" % event_filter.sql(api) +# with new filtering, caller needs to set this explicitly +# sql += " ORDER BY %s" % Event.primary_key self.selectall(sql) diff --git a/PLC/Faults.py b/PLC/Faults.py index 1b8bd0dd..e3d46e5b 100644 --- a/PLC/Faults.py +++ b/PLC/Faults.py @@ -5,7 +5,7 @@ # Mark Huang # # Copyright (C) 2004-2006 The Trustees of Princeton University -# $Id: Faults.py,v 1.2 2006/12/07 09:13:55 thierry Exp $ +# $Id: Faults.py 5574 2007-10-25 20:33:17Z thierry $ # import xmlrpclib diff --git a/PLC/Filter.py b/PLC/Filter.py index c20fd9c5..40634960 100644 --- a/PLC/Filter.py +++ b/PLC/Filter.py @@ -14,34 +14,56 @@ class Filter(Parameter, dict): """ A type of parameter that represents a filter on one or more columns of a database table. + Special features provide support for negation, upper and lower bounds, + as well as sorting and clipping. - field should be a dictionary of field names and types, e.g. - - {'node_id': Parameter(int, "Node identifier"), - 'hostname': Parameter(int, "Fully qualified hostname", max = 255), - ...} + fields should be a dictionary of field names and types Only filters on non-sequence type fields are supported. + example : fields = {'node_id': Parameter(int, "Node identifier"), + 'hostname': Parameter(int, "Fully qualified hostname", max = 255), + ...} + filter should be a dictionary of field names and values - representing an intersection (if join_with is AND) or union (if - join_with is OR) filter. If a value is a sequence type, then it - should represent a list of possible values for that field. + representing the criteria for filtering. + example : filter = { 'hostname' : '*.edu' , site_id : [34,54] } + Whether the filter represents an intersection (AND) or a union (OR) + of these criteria is determined by the join_with argument + provided to the sql method below + + Special features: - Special forms: * a field starting with the ~ character means negation. - example : { '~peer_id' : None } + example : filter = { '~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 + example : filter = { ']event_id' : 2305 } + example : filter = { '>time' : 1178531418 } + in this example the integer value denotes a unix timestamp + + * if a value is a sequence type, then it should represent + a list of possible values for that field + example : filter = { 'node_id' : [12,34,56] } + * a (string) value containing either a * or a % character is treated as a (sql) pattern; * are replaced with % that is the SQL wildcard character. - example : { 'hostname' : '*.jp' } + example : filter = { 'hostname' : '*.jp' } + + * fields starting with - are special and relate to row selection, i.e. sorting and clipping + * '-SORT' : a field name, or an ordered list of field names that are used for sorting + * these fields may start with + (default) or - for denoting increasing or decreasing order + example : filter = { '-SORT' : [ '+node_id', '-hostname' ] } + * '-OFFSET' : the number of first rows to be ommitted + * '-LIMIT' : the amount of rows to be returned + example : filter = { '-OFFSET' : 100, '-PAGE':25} + + A realistic example would read + GetNodes ( { 'hostname' : '*.edu' , '-SORT' : 'hostname' , '-OFFSET' : 30 , '-PAGE' : 25 } ) + and that would return nodes matching '*.edu' in alphabetical order from 31th to 55th """ def __init__(self, fields = {}, filter = {}, doc = "Attribute filter"): @@ -86,6 +108,10 @@ class Filter(Parameter, dict): else: assert join_with in ("AND", "OR") + # init + sorts = [] + clips = [] + for field, value in self.iteritems(): # handle negation, numeric comparisons # simple, 1-depth only mechanism @@ -93,6 +119,7 @@ class Filter(Parameter, dict): modifiers={'~' : False, '<' : False, '>' : False, '[' : False, ']' : False, + '-' : False, } for char in modifiers.keys(): @@ -101,45 +128,76 @@ class Filter(Parameter, dict): 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)): - # Turn empty list into (NULL) instead of invalid () - if not value: - value = [None] - - operator = "IN" - value = map(str, map(api.db.quote, value)) - value = "(%s)" % ", ".join(value) + # filter on fields + if not modifiers['-']: + if field not in self.fields: + raise PLCInvalidArgument, "Invalid filter field '%s'" % field + + if isinstance(value, (list, tuple, set)): + # Turn empty list into (NULL) instead of invalid () + if not value: + value = [None] + + operator = "IN" + value = map(str, map(api.db.quote, value)) + value = "(%s)" % ", ".join(value) + else: + if value is None: + operator = "IS" + value = "NULL" + elif isinstance(value, StringTypes) and \ + (value.find("*") > -1 or value.find("%") > -1): + operator = "LIKE" + value = str(api.db.quote(value.replace("*", "%"))) + else: + operator = "=" + 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 modifiers['~']: + clause = " ( NOT %s ) " % (clause) + + conditionals.append(clause) + # sorting and clipping else: - if value is None: - operator = "IS" - value = "NULL" - elif isinstance(value, StringTypes) and \ - (value.find("*") > -1 or value.find("%") > -1): - operator = "LIKE" - value = str(api.db.quote(value.replace("*", "%"))) - else: - operator = "=" - 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 modifiers['~']: - clause = " ( NOT %s ) " % (clause) - - conditionals.append(clause) - -# print 'sql=',(" %s " % join_with).join(conditionals) - return (" %s " % join_with).join(conditionals) + if field not in ('SORT','OFFSET','LIMIT'): + raise PLCInvalidArgument, "Invalid filter, unknown sort and clip field %r"%field + # sorting + if field == 'SORT': + if not isinstance(value,(list,tuple,set)): + value=[value] + for field in value: + order = 'ASC' + if field[0] == '+': + field = field[1:] + elif field[0] == '-': + field = field[1:] + order = 'DESC' + if field not in self.fields: + raise PLCInvalidArgument, "Invalid field %r in SORT filter"%field + sorts.append("%s %s"%(field,order)) + # clipping + elif field == 'OFFSET': + clips.append("OFFSET %d"%value) + # clipping continued + elif field == 'LIMIT' : + clips.append("LIMIT %d"%value) + + where_part = (" %s " % join_with).join(conditionals) + clip_part = "" + if sorts: + clip_part += " ORDER BY " + ",".join(sorts) + if clips: + clip_part += " " + " ".join(clips) +# print 'where_part=',where_part,'clip_part',clip_part + return (where_part,clip_part) diff --git a/PLC/GPG.py b/PLC/GPG.py index 13e55855..457c32bb 100644 --- a/PLC/GPG.py +++ b/PLC/GPG.py @@ -7,7 +7,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: GPG.py,v 1.6 2007/02/07 04:35:19 mlhuang Exp $ +# $Id: GPG.py 5574 2007-10-25 20:33:17Z thierry $ # import os diff --git a/PLC/InitScripts.py b/PLC/InitScripts.py index f425698f..9f864d2a 100644 --- a/PLC/InitScripts.py +++ b/PLC/InitScripts.py @@ -58,9 +58,9 @@ class InitScripts(Table): ints = filter(lambda x: isinstance(x, (int, long)), initscript_filter) strs = filter(lambda x: isinstance(x, StringTypes), initscript_filter) initscript_filter = Filter(InitScript.fields, {'initscript_id': ints, 'name': strs }) - sql += " AND (%s)" % initscript_filter.sql(api, "OR") + sql += " AND (%s) %s" % initscript_filter.sql(api, "OR") elif isinstance(initscript_filter, dict): initscript_filter = Filter(InitScript.fields, initscript_filter) - sql += " AND (%s)" % initscript_filter.sql(api, "AND") + sql += " AND (%s) %s" % initscript_filter.sql(api, "AND") self.selectall(sql) diff --git a/PLC/KeyTypes.py b/PLC/KeyTypes.py index 0092bf74..920662b0 100644 --- a/PLC/KeyTypes.py +++ b/PLC/KeyTypes.py @@ -4,7 +4,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: KeyTypes.py,v 1.3 2006/10/24 20:02:22 mlhuang Exp $ +# $Id: KeyTypes.py 5574 2007-10-25 20:33:17Z thierry $ # from PLC.Faults import * diff --git a/PLC/Keys.py b/PLC/Keys.py index b81442d5..8d22dc2e 100644 --- a/PLC/Keys.py +++ b/PLC/Keys.py @@ -117,6 +117,6 @@ class Keys(Table): key_filter = Filter(Key.fields, {'key_id': key_filter}) elif isinstance(key_filter, dict): key_filter = Filter(Key.fields, key_filter) - sql += " AND (%s)" % key_filter.sql(api) + sql += " AND (%s) %s" % key_filter.sql(api) self.selectall(sql) diff --git a/PLC/Messages.py b/PLC/Messages.py index 250ff12f..0620ac08 100644 --- a/PLC/Messages.py +++ b/PLC/Messages.py @@ -4,7 +4,7 @@ # Tony Mack # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: Messages.py,v 1.4 2006/11/16 17:03:36 mlhuang Exp $ +# $Id: Messages.py 5574 2007-10-25 20:33:17Z thierry $ # from PLC.Parameter import Parameter @@ -42,9 +42,9 @@ class Messages(Table): if message_filter is not None: if isinstance(message_filter, (list, tuple, set)): message_filter = Filter(Message.fields, {'message_id': message_filter}) - sql += " AND (%s)" % message_filter.sql(api, "OR") + sql += " AND (%s) %s" % message_filter.sql(api, "OR") elif isinstance(message_filter, dict): message_filter = Filter(Message.fields, message_filter) - sql += " AND (%s)" % message_filter.sql(api, "AND") + sql += " AND (%s) %s" % message_filter.sql(api, "AND") self.selectall(sql) diff --git a/PLC/Method.py b/PLC/Method.py index 1ba4eb1b..5e7d09a1 100644 --- a/PLC/Method.py +++ b/PLC/Method.py @@ -4,7 +4,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: Method.py,v 1.30 2007/09/12 17:52:27 tmack Exp $ +# $Id: Method.py 5574 2007-10-25 20:33:17Z thierry $ # import xmlrpclib diff --git a/PLC/NetworkMethods.py b/PLC/NetworkMethods.py index a3d306b8..d6b6a637 100644 --- a/PLC/NetworkMethods.py +++ b/PLC/NetworkMethods.py @@ -4,7 +4,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: NetworkMethods.py,v 1.3 2006/10/24 20:02:22 mlhuang Exp $ +# $Id: NetworkMethods.py 5574 2007-10-25 20:33:17Z thierry $ # from PLC.Faults import * diff --git a/PLC/NetworkTypes.py b/PLC/NetworkTypes.py index bab7af8b..b42b42ee 100644 --- a/PLC/NetworkTypes.py +++ b/PLC/NetworkTypes.py @@ -4,7 +4,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: NetworkTypes.py,v 1.3 2006/10/24 20:02:22 mlhuang Exp $ +# $Id: NetworkTypes.py 5574 2007-10-25 20:33:17Z thierry $ # from PLC.Faults import * diff --git a/PLC/NodeGroups.py b/PLC/NodeGroups.py index 90bd5f90..65b4a41c 100644 --- a/PLC/NodeGroups.py +++ b/PLC/NodeGroups.py @@ -4,13 +4,13 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: NodeGroups.py,v 1.18 2006/11/09 03:07:42 mlhuang Exp $ +# $Id: NodeGroups.py 5666 2007-11-06 21:52:21Z tmack $ # from types import StringTypes from PLC.Faults import * -from PLC.Parameter import Parameter +from PLC.Parameter import Parameter, Mixed from PLC.Filter import Filter from PLC.Debug import profile from PLC.Table import Row, Table @@ -33,6 +33,11 @@ class NodeGroup(Row): 'node_ids': Parameter([int], "List of nodes in this node group"), 'conf_file_ids': Parameter([int], "List of configuration files specific to this node group"), } + related_fields = { + 'conf_files': [Parameter(int, "ConfFile identifier")], + 'nodes': [Mixed(Parameter(int, "Node identifier"), + Parameter(str, "Fully qualified hostname"))] + } def validate_name(self, name): # Make sure name is not blank @@ -41,8 +46,8 @@ class NodeGroup(Row): # Make sure node group does not alredy exist conflicts = NodeGroups(self.api, [name]) - for nodegroup_id in conflicts: - if 'nodegroup_id' not in self or self['nodegroup_id'] != nodegroup_id: + for nodegroup in conflicts: + if 'nodegroup_id' not in self or self['nodegroup_id'] != nodegroup['nodegroup_id']: raise PLCInvalidArgument, "Node group name already in use" return name @@ -98,6 +103,59 @@ class NodeGroup(Row): self['node_ids'].remove(node_id) node['nodegroup_ids'].remove(nodegroup_id) + def associate_nodes(self, auth, field, value): + """ + Adds nodes found in value list to this nodegroup (using AddNodeToNodeGroup). + Deletes nodes not found in value list from this slice (using DeleteNodeFromNodeGroup). + """ + + assert 'node_ids' in self + assert 'nodegroup_id' in self + assert isinstance(value, list) + + (node_ids, hostnames) = self.separate_types(value)[0:2] + + # Translate hostnames into node_ids + if hostnames: + nodes = Nodes(self.api, hostnames, ['node_id']).dict('node_id') + node_ids += nodes.keys() + + # Add new ids, remove stale ids + if self['node_ids'] != node_ids: + from PLC.Methods.AddNodeToNodeGroup import AddNodeToNodeGroup + from PLC.Methods.DeleteNodeFromNodeGroup import DeleteNodeFromNodeGroup + new_nodes = set(node_ids).difference(self['node_ids']) + stale_nodes = set(self['node_ids']).difference(node_ids) + + for new_node in new_nodes: + AddNodeToNodeGroup.__call__(AddNodeToNodeGroup(self.api), auth, new_node, self['nodegroup_id']) + for stale_node in stale_nodes: + DeleteNodeFromNodeGroup.__call__(DeleteNodeFromNodeGroup(self.api), auth, stale_node, self['nodegroup_id']) + + def associate_conf_files(self, auth, field, value): + """ + Add conf_files found in value list (AddConfFileToNodeGroup) + Delets conf_files not found in value list (DeleteConfFileFromNodeGroup) + """ + + assert 'conf_file_ids' in self + assert 'nodegroup_id' in self + assert isinstance(value, list) + + conf_file_ids = self.separate_types(value)[0] + + if self['conf_file_ids'] != conf_file_ids: + from PLC.Methods.AddConfFileToNodeGroup import AddConfFileToNodeGroup + from PLC.Methods.DeleteConfFileFromNodeGroup import DeleteConfFileFromNodeGroup + new_conf_files = set(conf_file_ids).difference(self['conf_file_ids']) + stale_conf_files = set(self['conf_file_ids']).difference(conf_file_ids) + + for new_conf_file in new_conf_files: + AddConfFileToNodeGroup.__call__(AddConfFileToNodeGroup(self.api), auth, new_conf_file, self['nodegroup_id']) + for stale_conf_file in stale_conf_files: + DeleteConfFileFromNodeGroup.__call__(DeleteConfFileFromNodeGroup(self.api), auth, stale_conf_file, self['nodegroup_id']) + + class NodeGroups(Table): """ Representation of row(s) from the nodegroups table in the @@ -116,9 +174,9 @@ class NodeGroups(Table): ints = filter(lambda x: isinstance(x, (int, long)), nodegroup_filter) strs = filter(lambda x: isinstance(x, StringTypes), nodegroup_filter) nodegroup_filter = Filter(NodeGroup.fields, {'nodegroup_id': ints, 'name': strs}) - sql += " AND (%s)" % nodegroup_filter.sql(api, "OR") + sql += " AND (%s) %s" % nodegroup_filter.sql(api, "OR") elif isinstance(nodegroup_filter, dict): nodegroup_filter = Filter(NodeGroup.fields, nodegroup_filter) - sql += " AND (%s)" % nodegroup_filter.sql(api, "AND") + sql += " AND (%s) %s" % nodegroup_filter.sql(api, "AND") self.selectall(sql) diff --git a/PLC/NodeNetworkSettingTypes.py b/PLC/NodeNetworkSettingTypes.py index f2ff2144..69f36b75 100644 --- a/PLC/NodeNetworkSettingTypes.py +++ b/PLC/NodeNetworkSettingTypes.py @@ -1,7 +1,7 @@ # # Thierry Parmentelat - INRIA # -# $Revision: 1.1 $ +# $Revision: 5574 $ # from types import StringTypes @@ -70,13 +70,13 @@ class NodeNetworkSettingTypes(Table): ints = filter(lambda x: isinstance(x, (int, long)), nodenetwork_setting_type_filter) strs = filter(lambda x: isinstance(x, StringTypes), nodenetwork_setting_type_filter) nodenetwork_setting_type_filter = Filter(NodeNetworkSettingType.fields, {'nodenetwork_setting_type_id': ints, 'name': strs}) - sql += " AND (%s)" % nodenetwork_setting_type_filter.sql(api, "OR") + sql += " AND (%s) %s" % nodenetwork_setting_type_filter.sql(api, "OR") elif isinstance(nodenetwork_setting_type_filter, dict): nodenetwork_setting_type_filter = Filter(NodeNetworkSettingType.fields, nodenetwork_setting_type_filter) - sql += " AND (%s)" % nodenetwork_setting_type_filter.sql(api, "AND") + sql += " AND (%s) %s" % nodenetwork_setting_type_filter.sql(api, "AND") elif isinstance (nodenetwork_setting_type_filter, StringTypes): nodenetwork_setting_type_filter = Filter(NodeNetworkSettingType.fields, {'name':[nodenetwork_setting_type_filter]}) - sql += " AND (%s)" % nodenetwork_setting_type_filter.sql(api, "AND") + sql += " AND (%s) %s" % nodenetwork_setting_type_filter.sql(api, "AND") else: raise PLCInvalidArgument, "Wrong nodenetwork setting type filter %r"%nodenetwork_setting_type_filter diff --git a/PLC/NodeNetworkSettings.py b/PLC/NodeNetworkSettings.py index eddd1e21..bcf25065 100644 --- a/PLC/NodeNetworkSettings.py +++ b/PLC/NodeNetworkSettings.py @@ -1,7 +1,7 @@ # # Thierry Parmentelat - INRIA # -# $Revision: 1.1 $ +# $Revision: 5574 $ # from PLC.Faults import * from PLC.Parameter import Parameter @@ -51,7 +51,7 @@ class NodeNetworkSettings(Table): nodenetwork_setting_filter = Filter(NodeNetworkSetting.fields, {'nodenetwork_setting_id': [nodenetwork_setting_filter]}) else: raise PLCInvalidArgument, "Wrong nodenetwork setting filter %r"%nodenetwork_setting_filter - sql += " AND (%s)" % nodenetwork_setting_filter.sql(api) + sql += " AND (%s) %s" % nodenetwork_setting_filter.sql(api) self.selectall(sql) diff --git a/PLC/NodeNetworks.py b/PLC/NodeNetworks.py index 76811694..19229e6b 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.18 2007/09/12 17:52:27 tmack Exp $ +# $Id: NodeNetworks.py 5574 2007-10-25 20:33:17Z thierry $ # from types import StringTypes @@ -221,6 +221,6 @@ class NodeNetworks(Table): nodenetwork_filter = Filter(NodeNetwork.fields, {'nodenetwork_id': [nodenetwork_filter]}) else: raise PLCInvalidArgument, "Wrong node network filter %r"%nodenetwork_filter - sql += " AND (%s)" % nodenetwork_filter.sql(api) + sql += " AND (%s) %s" % nodenetwork_filter.sql(api) self.selectall(sql) diff --git a/PLC/Nodes.py b/PLC/Nodes.py index 1475ca22..ac7b1266 100644 --- a/PLC/Nodes.py +++ b/PLC/Nodes.py @@ -4,14 +4,14 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: Nodes.py 800 2007-08-30 03:49:35Z thierry $ +# $Id: Nodes.py 5654 2007-11-06 03:43:55Z tmack $ # from types import StringTypes import re from PLC.Faults import * -from PLC.Parameter import Parameter +from PLC.Parameter import Parameter, Mixed from PLC.Filter import Filter from PLC.Debug import profile from PLC.Table import Row, Table @@ -65,7 +65,17 @@ class Node(Row): 'peer_id': Parameter(int, "Peer to which this node belongs", nullok = True), 'peer_node_id': Parameter(int, "Foreign node identifier at peer", nullok = True), } - + related_fields = { + 'nodenetworks': [Mixed(Parameter(int, "NodeNetwork identifier"), + Filter(NodeNetwork.fields))], + 'nodegroups': [Mixed(Parameter(int, "NodeGroup identifier"), + Parameter(str, "NodeGroup name"))], + 'conf_files': [Parameter(int, "ConfFile identifier")], + 'slices': [Mixed(Parameter(int, "Slice identifier"), + Parameter(str, "Slice name"))], + 'slices_whitelist': [Mixed(Parameter(int, "Slice identifier"), + Parameter(str, "Slice name"))] + } # for Cache class_key = 'hostname' foreign_fields = ['boot_state','model','version'] @@ -124,6 +134,142 @@ class Node(Row): " where node_id = %d" % (self['node_id']) ) self.sync(commit) + def associate_nodenetworks(self, auth, field, value): + """ + Delete nodenetworks not found in value list (using DeleteNodeNetwor)k + Add nodenetworks found in value list (using AddNodeNetwork) + Updates nodenetworks found w/ nodenetwork_id in value list (using UpdateNodeNetwork) + """ + + assert 'nodenetworkp_ids' in self + assert 'node_id' in self + assert isinstance(value, list) + + (nodenetwork_ids, blank, nodenetworks) = self.separate_types(value) + + if self['nodenetwork_ids'] != nodenetwork_ids: + from PLC.Methods.DeleteNodeNetwork import DeleteNodeNetwork + + stale_nodenetworks = set(self['nodenetwork_ids']).difference(nodenetwork_ids) + + for stale_nodenetwork in stale_nodenetworks: + DeleteNodeNetwork.__call__(DeleteNodeNetwork(self.api), auth, stale_nodenetwork['nodenetwork_id']) + + def associate_nodegroups(self, auth, field, value): + """ + Add node to nodegroups found in value list (AddNodeToNodegroup) + Delete node from nodegroup not found in value list (DeleteNodeFromNodegroup) + """ + + from PLC.NodeGroups import NodeGroups + + assert 'nodegroup_ids' in self + assert 'node_id' in self + assert isinstance(value, list) + + (nodegroup_ids, nodegroup_names) = self.separate_types(value)[0:2] + + if nodegroup_names: + nodegroups = NodeGroups(self.api, nodegroup_names, ['nodegroup_id']).dict('nodegroup_id') + nodegroup_ids += nodegroups.keys() + + if self['nodegroup_ids'] != nodegroup_ids: + from PLC.Methods.AddNodeToNodeGroup import AddNodeToNodeGroup + from PLC.Methods.DeleteNodeFromNodeGroup import DeleteNodeFromNodeGroup + + new_nodegroups = set(nodegroup_ids).difference(self['nodegroup_ids']) + stale_nodegroups = set(self['nodegroup_ids']).difference(nodegroup_ids) + + for new_nodegroup in new_nodegroups: + AddNodeToNodeGroup.__call__(AddNodeToNodeGroup(self.api), auth, self['node_id'], new_nodegroup) + for stale_nodegroup in stale_nodegroups: + DeleteNodeFromNodeGroup.__call__(DeleteNodeFromNodeGroup(self.api), auth, self['node_id'], stale_nodegroup) + + + + def associate_conf_files(self, auth, field, value): + """ + Add conf_files found in value list (AddConfFileToNode) + Delets conf_files not found in value list (DeleteConfFileFromNode) + """ + + assert 'conf_file_ids' in self + assert 'node_id' in self + assert isinstance(value, list) + + conf_file_ids = self.separate_types(value)[0] + + if self['conf_file_ids'] != conf_file_ids: + from PLC.Methods.AddConfFileToNode import AddConfFileToNode + from PLC.Methods.DeleteConfFileFromNode import DeleteConfFileFromNode + new_conf_files = set(conf_file_ids).difference(self['conf_file_ids']) + stale_conf_files = set(self['conf_file_ids']).difference(conf_file_ids) + + for new_conf_file in new_conf_files: + AddConfFileToNode.__call__(AddConfFileToNode(self.api), auth, new_conf_file, self['node_id']) + for stale_conf_file in stale_conf_files: + DeleteConfFileFromNode.__call__(DeleteConfFileFromNode(self.api), auth, stale_conf_file, self['node_id']) + + + def associate_slices(self, auth, field, value): + """ + Add slices found in value list to (AddSliceToNode) + Delete slices not found in value list (DeleteSliceFromNode) + """ + + from PLC.Slices import Slices + + assert 'slice_ids' in self + assert 'node_id' in self + assert isinstance(value, list) + + (slice_ids, slice_names) = self.separate_types(value)[0:2] + + if slice_names: + slices = Slices(self.api, slice_names, ['slice_id']).dict('slice_id') + slice_ids += slices.keys() + + if self['slice_ids'] != slice_ids: + from PLC.Methods.AddSliceToNodes import AddSliceToNodes + from PLC.Methods.DeleteSliceFromNodes import DeleteSliceFromNodes + new_slices = set(slice_ids).difference(self['slice_ids']) + stale_slices = set(self['slice_ids']).difference(slice_ids) + + for new_slice in new_slices: + AddSliceToNodes.__call__(AddSliceToNodes(self.api), auth, new_slice, [self['node_id']]) + for stale_slice in stale_slices: + DeleteSliceFromNodes.__call__(DeleteSliceFromNodes(self.api), auth, stale_slice, [self['node_id']]) + + def associate_slices_whitelist(self, auth, field, value): + """ + Add slices found in value list to whitelist (AddSliceToNodesWhitelist) + Delete slices not found in value list from whitelist (DeleteSliceFromNodesWhitelist) + """ + + from PLC.Slices import Slices + + assert 'slice_ids_whitelist' in self + assert 'node_id' in self + assert isinstance(value, list) + + (slice_ids, slice_names) = self.separate_types(value)[0:2] + + if slice_names: + slices = Slices(self.api, slice_names, ['slice_id']).dict('slice_id') + slice_ids += slices.keys() + + if self['slice_ids_whitelist'] != slice_ids: + from PLC.Methods.AddSliceToNodesWhitelist import AddSliceToNodesWhitelist + from PLC.Methods.DeleteSliceFromNodesWhitelist import DeleteSliceFromNodesWhitelist + new_slices = set(slice_ids).difference(self['slice_ids_whitelist']) + stale_slices = set(self['slice_ids_whitelist']).difference(slice_ids) + + for new_slice in new_slices: + AddSliceToNodesWhitelist.__call__(AddSliceToNodesWhitelist(self.api), auth, new_slice, [self['node_id']]) + for stale_slice in stale_slices: + DeleteSliceFromNodesWhitelist.__call__(DeleteSliceFromNodesWhitelist(self.api), auth, stale_slice, [self['node_id']]) + + def delete(self, commit = True): """ Delete existing node. @@ -164,16 +310,16 @@ class Nodes(Table): ints = filter(lambda x: isinstance(x, (int, long)), node_filter) strs = filter(lambda x: isinstance(x, StringTypes), node_filter) node_filter = Filter(Node.fields, {'node_id': ints, 'hostname': strs}) - sql += " AND (%s)" % node_filter.sql(api, "OR") + sql += " AND (%s) %s" % node_filter.sql(api, "OR") elif isinstance(node_filter, dict): node_filter = Filter(Node.fields, node_filter) - sql += " AND (%s)" % node_filter.sql(api, "AND") + sql += " AND (%s) %s" % node_filter.sql(api, "AND") elif isinstance (node_filter, StringTypes): node_filter = Filter(Node.fields, {'hostname':[node_filter]}) - sql += " AND (%s)" % node_filter.sql(api, "AND") + sql += " AND (%s) %s" % node_filter.sql(api, "AND") elif isinstance (node_filter, int): node_filter = Filter(Node.fields, {'node_id':[node_filter]}) - sql += " AND (%s)" % node_filter.sql(api, "AND") + sql += " AND (%s) %s" % node_filter.sql(api, "AND") else: raise PLCInvalidArgument, "Wrong node filter %r"%node_filter diff --git a/PLC/PCUProtocolTypes.py b/PLC/PCUProtocolTypes.py new file mode 100644 index 00000000..30ef4592 --- /dev/null +++ b/PLC/PCUProtocolTypes.py @@ -0,0 +1,75 @@ +# +# Functions for interacting with the pcu_type_port table in the database +# +# Mark Huang +# Copyright (C) 2006 The Trustees of Princeton University +# +# $Id: +# + +from PLC.Faults import * +from PLC.Parameter import Parameter +from PLC.Table import Row, Table +from PLC.Filter import Filter + +class PCUProtocolType(Row): + """ + Representation of a row in the pcu_protocol_type table. To use, + instantiate with a dict of values. + """ + + table_name = 'pcu_protocol_type' + primary_key = 'pcu_protocol_type_id' + join_tables = [] + fields = { + 'pcu_protocol_type_id': Parameter(int, "PCU protocol type identifier"), + 'pcu_type_id': Parameter(int, "PCU type identifier"), + 'port': Parameter(int, "PCU port", max = 254), + 'protocol': Parameter(str, "Protocol", max = 254), + 'supported': Parameter(bool, "Is the port/protocol supported by PLC") + } + + def validate_port(self, port): + # make sure port is not blank + + if not port: + raise PLCInvalidArgument, "Port must be specified" + + return port + + def validate_protocol(self, protocol): + # make sure port is not blank + if not len(protocol): + raise PLCInvalidArgument, "protocol must be specified" + + return protocol + +class PCUProtocolTypes(Table): + """ + Representation of the pcu_protocol_types table in the database. + """ + + def __init__(self, api, protocol_type_filter = None, columns = None): + Table.__init__(self, api, PCUProtocolType, columns) + + sql = "SELECT %s FROM pcu_protocol_type WHERE True" % \ + ", ".join(self.columns) + + if protocol_type_filter is not None: + if isinstance(protocol_type_filter, (list, tuple, set)): + # Separate the list into integers and strings + ints = filter(lambda x: isinstance(x, (int, long)), protocol_type_filter) + protocol_type_filter = Filter(PCUProtocolType.fields, {'pcu_protocol_type_id': ints}) + sql += " AND (%s) %s" % protocol_type_filter.sql(api, "OR") + elif isinstance(protocol_type_filter, dict): + protocol_type_filter = Filter(PCUProtocolType.fields, protocol_type_filter) + sql += " AND (%s) %s" % protocol_type_filter.sql(api, "AND") + elif isinstance (protocol_type_filter, int): + protocol_type_filter = Filter(PCUProtocolType.fields, {'pcu_protocol_type_id':[protocol_type_filter]}) + + sql += " AND (%s) %s" % protocol_type_filter.sql(api, "AND") + else: + raise PLCInvalidArgument, "Wrong pcu_protocol_type filter %r"%protocol_type_filter + + + self.selectall(sql) diff --git a/PLC/PCUTypes.py b/PLC/PCUTypes.py new file mode 100644 index 00000000..d1f650c6 --- /dev/null +++ b/PLC/PCUTypes.py @@ -0,0 +1,104 @@ +# +# Functions for interacting with the pcu_types table in the database +# +# Mark Huang +# Copyright (C) 2006 The Trustees of Princeton University +# +# $Id: +# +from types import StringTypes + +from PLC.Faults import * +from PLC.Parameter import Parameter +from PLC.Table import Row, Table +from PLC.Filter import Filter + +class PCUType(Row): + """ + Representation of a row in the pcu_types table. To use, + instantiate with a dict of values. + """ + + table_name = 'pcu_types' + primary_key = 'pcu_type_id' + join_tables = ['pcu_port_type'] + fields = { + 'pcu_type_id': Parameter(int, "PCU Type Identifier"), + 'model': Parameter(str, "PCU model", max = 254), + 'name': Parameter(str, "PCU full name", max = 254), + 'pcu_protocol_type_ids': Parameter([int], "PCU Protocol Type Identifiers"), + 'pcu_protocol_types': Parameter([dict], "PCU Protocol Type List") + } + + def validate_model(self, model): + # Make sure name is not blank + if not len(model): + raise PLCInvalidArgument, "Model must be specified" + + # Make sure boot state does not alredy exist + conflicts = PCUTypes(self.api, [model]) + for pcu_type in conflicts: + if 'pcu_type_id' not in self or self['pcu_type_id'] != pcu_type['pcu_type_id']: + raise PLCInvalidArgument, "Model already in use" + + return model + +class PCUTypes(Table): + """ + Representation of the pcu_types table in the database. + """ + + def __init__(self, api, pcu_type_filter = None, columns = None): + + # Remove pcu_protocol_types from query since its not really a field + # in the db. We will add it later + if columns == None: + columns = PCUType.fields.keys() + if 'pcu_protocol_types' in columns: + removed_fields = ['pcu_protocol_types'] + columns.remove('pcu_protocol_types') + else: + removed_fields = [] + + Table.__init__(self, api, PCUType, columns) + + sql = "SELECT %s FROM view_pcu_types WHERE True" % \ + ", ".join(self.columns) + + if pcu_type_filter is not None: + if isinstance(pcu_type_filter, (list, tuple, set)): + # Separate the list into integers and strings + ints = filter(lambda x: isinstance(x, (int, long)), pcu_type_filter) + strs = filter(lambda x: isinstance(x, StringTypes), pcu_type_filter) + pcu_type_filter = Filter(PCUType.fields, {'pcu_type_id': ints, 'model': strs}) + sql += " AND (%s) %s" % pcu_type_filter.sql(api, "OR") + elif isinstance(pcu_type_filter, dict): + pcu_type_filter = Filter(PCUType.fields, pcu_type_filter) + sql += " AND (%s) %s" % pcu_type_filter.sql(api, "AND") + elif isinstance (pcu_type_filter, StringTypes): + pcu_type_filter = Filter(PCUType.fields, {'model':[pcu_type_filter]}) + sql += " AND (%s) %s" % pcu_type_filter.sql(api, "AND") + elif isinstance (pcu_type_filter, int): + pcu_type_filter = Filter(PCUType.fields, {'pcu_type_id':[pcu_type_filter]}) + sql += " AND (%s) %s" % pcu_type_filter.sql(api, "AND") + else: + raise PLCInvalidArgument, "Wrong pcu_type filter %r"%pcu_type_filter + + + self.selectall(sql) + + # return a list of protocol type objects for each port type + if 'pcu_protocol_types' in removed_fields: + from PLC.PCUProtocolTypes import PCUProtocolTypes + protocol_type_ids = set() + for pcu_type in self: + protocol_type_ids.update(pcu_type['pcu_protocol_type_ids']) + + protocol_return_fields = ['pcu_protocol_type_id', 'port', 'protocol', 'supported'] + all_protocol_types = PCUProtocolTypes(self.api, list(protocol_type_ids), \ + protocol_return_fields).dict('pcu_protocol_type_id') + + for pcu_type in self: + pcu_type['pcu_protocol_types'] = [] + for protocol_type_id in pcu_type['pcu_protocol_type_ids']: + pcu_type['pcu_protocol_types'].append(all_protocol_types[protocol_type_id]) diff --git a/PLC/PCUs.py b/PLC/PCUs.py index 5b69c0aa..0ab56cc7 100644 --- a/PLC/PCUs.py +++ b/PLC/PCUs.py @@ -4,7 +4,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: PCUs.py,v 1.9 2006/11/09 03:07:42 mlhuang Exp $ +# $Id: PCUs.py 5574 2007-10-25 20:33:17Z thierry $ # from PLC.Faults import * @@ -111,6 +111,6 @@ class PCUs(Table): pcu_filter = Filter(PCU.fields, {'pcu_id': pcu_filter}) elif isinstance(pcu_filter, dict): pcu_filter = Filter(PCU.fields, pcu_filter) - sql += " AND (%s)" % pcu_filter.sql(api) + sql += " AND (%s) %s" % pcu_filter.sql(api) self.selectall(sql) diff --git a/PLC/Parameter.py b/PLC/Parameter.py index 23074836..474ad78a 100644 --- a/PLC/Parameter.py +++ b/PLC/Parameter.py @@ -4,7 +4,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: Parameter.py,v 1.6 2006/11/08 22:10:00 mlhuang Exp $ +# $Id: Parameter.py 5574 2007-10-25 20:33:17Z thierry $ # from types import * diff --git a/PLC/Peers.py b/PLC/Peers.py index b1de5e7f..0973c3d4 100644 --- a/PLC/Peers.py +++ b/PLC/Peers.py @@ -227,9 +227,9 @@ class Peers (Table): ints = filter(lambda x: isinstance(x, (int, long)), peer_filter) strs = filter(lambda x: isinstance(x, StringTypes), peer_filter) peer_filter = Filter(Peer.fields, {'peer_id': ints, 'peername': strs}) - sql += " AND (%s)" % peer_filter.sql(api, "OR") + sql += " AND (%s) %s" % peer_filter.sql(api, "OR") elif isinstance(peer_filter, dict): peer_filter = Filter(Peer.fields, peer_filter) - sql += " AND (%s)" % peer_filter.sql(api, "AND") + sql += " AND (%s) %s" % peer_filter.sql(api, "AND") self.selectall(sql) diff --git a/PLC/Persons.py b/PLC/Persons.py index f035955e..d2bb510d 100644 --- a/PLC/Persons.py +++ b/PLC/Persons.py @@ -4,7 +4,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: Persons.py,v 1.39 2007/10/01 20:51:46 tmack Exp $ +# $Id: Persons.py 5652 2007-11-06 03:42:57Z tmack $ # from types import StringTypes @@ -17,7 +17,7 @@ import crypt from PLC.Faults import * from PLC.Debug import log -from PLC.Parameter import Parameter +from PLC.Parameter import Parameter, Mixed from PLC.Filter import Filter from PLC.Table import Row, Table from PLC.Roles import Role, Roles @@ -57,6 +57,18 @@ class Person(Row): 'peer_id': Parameter(int, "Peer to which this user belongs", nullok = True), 'peer_person_id': Parameter(int, "Foreign user identifier at peer", nullok = True), } + related_fields = { + 'roles': [Mixed(Parameter(int, "Role identifier"), + Parameter(str, "Role name"))], + 'sites': [Mixed(Parameter(int, "Site identifier"), + Parameter(str, "Site name"))], + 'keys': [Mixed(Parameter(int, "Key identifier"), + Filter(Key.fields))], + 'slices': [Mixed(Parameter(int, "Slice identifier"), + Parameter(str, "Slice name"))] + } + + # for Cache class_key = 'email' @@ -229,6 +241,132 @@ class Person(Row): " where person_id = %d" % (self['person_id']) ) self.sync(commit) + def associate_roles(self, auth, field, value): + """ + Adds roles found in value list to this person (using AddRoleToPerson). + Deletes roles not found in value list from this person (using DeleteRoleFromPerson). + """ + + assert 'role_ids' in self + assert 'person_id' in self + assert isinstance(value, list) + + (role_ids, roles_names) = self.separate_types(value)[0:2] + + # Translate roles into role_ids + if roles_names: + roles = Roles(self.api, role_names, ['role_id']).dict('role_id') + role_ids += roles.keys() + + # Add new ids, remove stale ids + if self['role_ids'] != role_ids: + from PLC.Methods.AddRoleToPerson import AddRoleToPerson + from PLC.Methods.DeleteRoleFromPerson import DeleteRoleFromPerson + new_roles = set(role_ids).difference(self['role_ids']) + stale_roles = set(self['role_ids']).difference(role_ids) + + for new_role in new_roles: + AddRoleToPerson.__call__(AddRoleToPerson(self.api), auth, new_role, self['person_id']) + for stale_role in stale_roles: + DeleteRoleFromPerson.__call__(DeleteRoleFromPerson(self.api), auth, stale_role, self['person_id']) + + + def associate_sites(self, auth, field, value): + """ + Adds person to sites found in value list (using AddPersonToSite). + Deletes person from site not found in value list (using DeletePersonFromSite). + """ + + from PLC.Sites import Sites + + assert 'site_ids' in self + assert 'person_id' in self + assert isinstance(value, list) + + (site_ids, site_names) = self.separate_types(value)[0:2] + + # Translate roles into role_ids + if site_names: + sites = Sites(self.api, site_names, ['site_id']).dict('site_id') + site_ids += sites.keys() + + # Add new ids, remove stale ids + if self['site_ids'] != site_ids: + from PLC.Methods.AddPersonToSite import AddPersonToSite + from PLC.Methods.DeletePersonFromSite import DeletePersonFromSite + new_sites = set(site_ids).difference(self['site_ids']) + stale_sites = set(self['site_ids']).difference(site_ids) + + for new_site in new_sites: + AddPersonToSite.__call__(AddPersonToSite(self.api), auth, self['person_id'], new_site) + for stale_site in stale_sites: + DeletePersonFromSite.__call__(DeletePersonFromSite(self.api), auth, self['person_id'], stale_site) + + + def associate_keys(self, auth, field, value): + """ + Deletes key_ids not found in value list (using DeleteKey). + Adds key if key_fields w/o key_id is found (using AddPersonKey). + Updates key if key_fields w/ key_id is found (using UpdateKey). + """ + assert 'key_ids' in self + assert 'person_id' in self + assert isinstance(value, list) + + (key_ids, blank, keys) = self.separate_types(value) + + if self['key_ids'] != key_ids: + from PLC.Methods.DeleteKey import DeleteKey + stale_keys = set(self['key_ids']).difference(key_ids) + + for stale_key in stale_keys: + DeleteKey.__call__(DeleteKey(self.api), auth, stale_key) + + if keys: + from PLC.Methods.AddPersonKey import AddPersonKey + from PLC.Methods.UpdateKey import UpdateKey + updated_keys = filter(lambda key: 'key_id' in key, keys) + added_keys = filter(lambda key: 'key_id' not in key, keys) + + for key in added_keys: + AddPersonKey.__call__(AddPersonKey(self.api), auth, self['person_id'], key) + for key in updated_keys: + key_id = key.pop('key_id') + UpdateKey.__call__(UpdateKey(self.api), auth, key_id, key) + + + def associate_slices(self, auth, field, value): + """ + Adds person to slices found in value list (using AddPersonToSlice). + Deletes person from slices found in value list (using DeletePersonFromSlice). + """ + + from PLC.Slices import Slices + + assert 'slice_ids' in self + assert 'person_id' in self + assert isinstance(value, list) + + (slice_ids, slice_names) = self.separate_types(value)[0:2] + + # Translate roles into role_ids + if slice_names: + slices = Slices(self.api, slice_names, ['slice_id']).dict('slice_id') + slice_ids += slices.keys() + + # Add new ids, remove stale ids + if self['slice_ids'] != slice_ids: + from PLC.Methods.AddPersonToSlice import AddPersonToSlice + from PLC.Methods.DeletePersonFromSlice import DeletePersonFromSlice + new_slices = set(slice_ids).difference(self['slice_ids']) + stale_slices = set(self['slice_ids']).difference(slice_ids) + + for new_slice in new_slices: + AddPersonToSlice.__call__(AddPersonToSlice(self.api), auth, self['person_id'], new_slice) + for stale_slice in stale_slices: + DeletePersonFromSlice.__call__(DeletePersonFromSlice(self.api), auth, self['person_id'], stale_slice) + + def delete(self, commit = True): """ Delete existing user. @@ -322,18 +460,18 @@ class Persons(Table): ints = filter(lambda x: isinstance(x, (int, long)), person_filter) strs = filter(lambda x: isinstance(x, StringTypes), person_filter) person_filter = Filter(Person.fields, {'person_id': ints, 'email': strs}) - sql += " AND (%s)" % person_filter.sql(api, "OR") + sql += " AND (%s) %s" % person_filter.sql(api, "OR") elif isinstance(person_filter, dict): person_filter = Filter(Person.fields, person_filter) - sql += " AND (%s)" % person_filter.sql(api, "AND") - elif isinstance (person_filter, StringTypes): + sql += " AND (%s) %s" % person_filter.sql(api, "AND") + elif isinstance (person_filter, StringTypes): person_filter = Filter(Person.fields, {'email':[person_filter]}) - sql += " AND (%s)" % person_filter.sql(api, "AND") + sql += " AND (%s) %s" % person_filter.sql(api, "AND") elif isinstance (person_filter, int): person_filter = Filter(Person.fields, {'person_id':[person_filter]}) - sql += " AND (%s)" % person_filter.sql(api, "AND") - else: - raise PLCInvalidArgument, "Wrong person filter %r"%person_filter + sql += " AND (%s) %s" % person_filter.sql(api, "AND") + else: + raise PLCInvalidArgument, "Wrong person filter %r"%person_filter # aggregate data all_persons = {} diff --git a/PLC/PostgreSQL.py b/PLC/PostgreSQL.py index 9100ce17..c58a69fc 100644 --- a/PLC/PostgreSQL.py +++ b/PLC/PostgreSQL.py @@ -5,7 +5,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: PostgreSQL.py,v 1.15 2007/02/12 18:41:27 mlhuang Exp $ +# $Id: PostgreSQL.py 5574 2007-10-25 20:33:17Z thierry $ # import psycopg2 diff --git a/PLC/PyCurl.py b/PLC/PyCurl.py index 51b08a36..032ab755 100644 --- a/PLC/PyCurl.py +++ b/PLC/PyCurl.py @@ -5,7 +5,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: PyCurl.py,v 1.3 2007/10/01 20:51:47 tmack Exp $ +# $Id: PyCurl.py 5574 2007-10-25 20:33:17Z thierry $ # import os diff --git a/PLC/Roles.py b/PLC/Roles.py index 86477668..53d68d01 100644 --- a/PLC/Roles.py +++ b/PLC/Roles.py @@ -4,7 +4,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: Roles.py,v 1.7 2006/11/08 23:02:01 mlhuang Exp $ +# $Id: Roles.py 5574 2007-10-25 20:33:17Z thierry $ # from types import StringTypes @@ -64,9 +64,9 @@ class Roles(Table): ints = filter(lambda x: isinstance(x, (int, long)), role_filter) strs = filter(lambda x: isinstance(x, StringTypes), role_filter) role_filter = Filter(Role.fields, {'role_id': ints, 'name': strs}) - sql += " AND (%s)" % role_filter.sql(api, "OR") + sql += " AND (%s) %s" % role_filter.sql(api, "OR") elif isinstance(role_filter, dict): role_filter = Filter(Role.fields, role_filter) - sql += " AND (%s)" % role_filter.sql(api, "AND") + sql += " AND (%s) %s" % role_filter.sql(api, "AND") self.selectall(sql) diff --git a/PLC/Sessions.py b/PLC/Sessions.py index b470c963..e0a57b32 100644 --- a/PLC/Sessions.py +++ b/PLC/Sessions.py @@ -76,10 +76,10 @@ class Sessions(Table): 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") + sql += " AND (%s) %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") + sql += " AND (%s) %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 6782fff3..43317a02 100644 --- a/PLC/Shell.py +++ b/PLC/Shell.py @@ -5,7 +5,7 @@ # Mark Huang # Copyright (C) 2005 The Trustees of Princeton University # -# $Id: Shell.py,v 1.5 2007/02/08 21:49:24 mlhuang Exp $ +# $Id: Shell.py 5574 2007-10-25 20:33:17Z thierry $ # import os diff --git a/PLC/Sites.py b/PLC/Sites.py index 759e1d79..6035bb78 100644 --- a/PLC/Sites.py +++ b/PLC/Sites.py @@ -2,7 +2,7 @@ from types import StringTypes import string from PLC.Faults import * -from PLC.Parameter import Parameter +from PLC.Parameter import Parameter, Mixed from PLC.Filter import Filter from PLC.Debug import profile from PLC.Table import Row, Table @@ -45,7 +45,12 @@ class Site(Row): 'peer_site_id': Parameter(int, "Foreign site identifier at peer", nullok = True), 'ext_consortium_id': Parameter(int, "external consortium id", nullok = True) } - + related_fields = { + 'persons': [Mixed(Parameter(int, "Person identifier"), + Parameter(str, "Email address"))], + 'addresses': [Mixed(Parameter(int, "Address identifer"), + Filter(Address.fields))] + } # for Cache class_key = 'login_base' foreign_fields = ['abbreviated_name', 'name', 'is_public', 'latitude', 'longitude', @@ -113,6 +118,74 @@ class Site(Row): " where site_id = %d" % (self['site_id']) ) self.sync(commit) + + def associate_persons(self, auth, field, value): + """ + Adds persons found in value list to this site (using AddPersonToSite). + Deletes persons not found in value list from this site (using DeletePersonFromSite). + """ + + assert 'person_ids' in self + assert 'site_id' in self + assert isinstance(value, list) + + (person_ids, emails) = self.separate_types(value)[0:2] + + # Translate emails into person_ids + if emails: + persons = Persons(self.api, emails, ['person_id']).dict('person_id') + person_ids += persons.keys() + + # Add new ids, remove stale ids + if self['person_ids'] != person_ids: + from PLC.Methods.AddPersonToSite import AddPersonToSite + from PLC.Methods.DeletePersonFromSite import DeletePersonFromSite + new_persons = set(person_ids).difference(self['person_ids']) + stale_persons = set(self['person_ids']).difference(person_ids) + + for new_person in new_persons: + AddPersonToSite.__call__(AddPersonToSite(self.api), auth, new_person, self['site_id']) + for stale_person in stale_persons: + DeletePersonFromSite.__call__(DeletePersonFromSite(self.api), auth, stale_person, self['site_id']) + + def associate_addresses(self, auth, field, value): + """ + Deletes addresses_ids not found in value list (using DeleteAddress). + Adds address if slice_fields w/o address_id found in value list (using AddSiteAddress). + Update address if slice_fields w/ address_id found in value list (using UpdateAddress). + """ + + assert 'address_ids' in self + assert 'site_id' in self + assert isinstance(value, list) + + (address_ids, blank, addresses) = self.separate_types(value) + + for address in addresses: + if 'address_id' in address: + address_ids.append(address['address_id']) + + # Add new ids, remove stale ids + if self['address_ids'] != address_ids: + from PLC.Methods.DeleteAddress import DeleteAddress + stale_addresses = set(self['address_ids']).difference(address_ids) + + for stale_address in stale_addresses: + DeleteAddress.__call__(DeleteAddress(self.api), auth, stale_address) + + if addresses: + from PLC.Methods.AddSiteAddress import AddSiteAddress + from PLC.Methods.UpdateAddress import UpdateAddress + + updated_addresses = filter(lambda address: 'address_id' in address, addresses) + added_addresses = filter(lambda address: 'address_id' not in address, addresses) + + for address in added_addresses: + AddSiteAddress.__call__(AddSiteAddress(self.api), auth, self['site_id'], address) + for address in updated_addresses: + address_id = address.pop('address_id') + UpdateAddress.__call__(UpdateAddress(self.api), auth, address_id, address) + def delete(self, commit = True): """ Delete existing site. @@ -182,16 +255,16 @@ class Sites(Table): ints = filter(lambda x: isinstance(x, (int, long)), site_filter) strs = filter(lambda x: isinstance(x, StringTypes), site_filter) site_filter = Filter(Site.fields, {'site_id': ints, 'login_base': strs}) - sql += " AND (%s)" % site_filter.sql(api, "OR") + sql += " AND (%s) %s" % site_filter.sql(api, "OR") elif isinstance(site_filter, dict): site_filter = Filter(Site.fields, site_filter) - sql += " AND (%s)" % site_filter.sql(api, "AND") - elif isinstance (site_filter, StringTypes): + sql += " AND (%s) %s" % site_filter.sql(api, "AND") + elif isinstance (site_filter, StringTypes): site_filter = Filter(Site.fields, {'login_base':[site_filter]}) - sql += " AND (%s)" % site_filter.sql(api, "AND") + sql += " AND (%s) %s" % site_filter.sql(api, "AND") elif isinstance (site_filter, int): site_filter = Filter(Site.fields, {'site_id':[site_filter]}) - sql += " AND (%s)" % site_filter.sql(api, "AND") + sql += " AND (%s) %s" % site_filter.sql(api, "AND") else: raise PLCInvalidArgument, "Wrong site filter %r"%site_filter diff --git a/PLC/SliceAttributeTypes.py b/PLC/SliceAttributeTypes.py index 6aa4baa2..5884fe0a 100644 --- a/PLC/SliceAttributeTypes.py +++ b/PLC/SliceAttributeTypes.py @@ -64,9 +64,9 @@ class SliceAttributeTypes(Table): ints = filter(lambda x: isinstance(x, (int, long)), attribute_type_filter) strs = filter(lambda x: isinstance(x, StringTypes), attribute_type_filter) attribute_type_filter = Filter(SliceAttributeType.fields, {'attribute_type_id': ints, 'name': strs}) - sql += " AND (%s)" % attribute_type_filter.sql(api, "OR") + sql += " AND (%s) %s" % attribute_type_filter.sql(api, "OR") elif isinstance(attribute_type_filter, dict): attribute_type_filter = Filter(SliceAttributeType.fields, attribute_type_filter) - sql += " AND (%s)" % attribute_type_filter.sql(api, "AND") + sql += " AND (%s) %s" % attribute_type_filter.sql(api, "AND") self.selectall(sql) diff --git a/PLC/SliceAttributes.py b/PLC/SliceAttributes.py index cfc0298d..9f0b1fbe 100644 --- a/PLC/SliceAttributes.py +++ b/PLC/SliceAttributes.py @@ -41,6 +41,6 @@ class SliceAttributes(Table): slice_attribute_filter = Filter(SliceAttribute.fields, {'slice_attribute_id': slice_attribute_filter}) elif isinstance(slice_attribute_filter, dict): slice_attribute_filter = Filter(SliceAttribute.fields, slice_attribute_filter) - sql += " AND (%s)" % slice_attribute_filter.sql(api) + sql += " AND (%s) %s" % slice_attribute_filter.sql(api) self.selectall(sql) diff --git a/PLC/SliceInstantiations.py b/PLC/SliceInstantiations.py index 843b3270..db118388 100644 --- a/PLC/SliceInstantiations.py +++ b/PLC/SliceInstantiations.py @@ -4,7 +4,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: SliceInstantiations.py,v 1.2 2006/10/03 19:27:28 mlhuang Exp $ +# $Id: SliceInstantiations.py 5574 2007-10-25 20:33:17Z thierry $ # from PLC.Faults import * diff --git a/PLC/Slices.py b/PLC/Slices.py index 88c0b579..1a1786c8 100644 --- a/PLC/Slices.py +++ b/PLC/Slices.py @@ -3,13 +3,14 @@ import time import re from PLC.Faults import * -from PLC.Parameter import Parameter +from PLC.Parameter import Parameter, Mixed 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 from PLC.Persons import Person, Persons +from PLC.SliceAttributes import SliceAttribute class Slice(Row): """ @@ -39,6 +40,12 @@ class Slice(Row): 'peer_id': Parameter(int, "Peer to which this slice belongs", nullok = True), 'peer_slice_id': Parameter(int, "Foreign slice identifier at peer", nullok = True), } + related_fields = { + 'persons': [Mixed(Parameter(int, "Person identifier"), + Parameter(str, "Email address"))], + 'nodes': [Mixed(Parameter(int, "Node identifier"), + Parameter(str, "Fully qualified hostname"))] + } # for Cache class_key = 'name' foreign_fields = ['instantiation', 'url', 'description', 'max_nodes', 'expires'] @@ -97,6 +104,127 @@ class Slice(Row): add_to_node_whitelist = Row.add_object(Node, 'node_slice_whitelist') delete_from_node_whitelist = Row.remove_object(Node, 'node_slice_whitelist') + def associate_persons(self, auth, field, value): + """ + Adds persons found in value list to this slice (using AddPersonToSlice). + Deletes persons not found in value list from this slice (using DeletePersonFromSlice). + """ + + assert 'person_ids' in self + assert 'slice_id' in self + assert isinstance(value, list) + + (person_ids, emails) = self.separate_types(value)[0:2] + + # Translate emails into person_ids + if emails: + persons = Persons(self.api, emails, ['person_id']).dict('person_id') + person_ids += persons.keys() + + # Add new ids, remove stale ids + if self['person_ids'] != person_ids: + from PLC.Methods.AddPersonToSlice import AddPersonToSlice + from PLC.Methods.DeletePersonFromSlice import DeletePersonFromSlice + new_persons = set(person_ids).difference(self['person_ids']) + stale_persons = set(self['person_ids']).difference(person_ids) + + for new_person in new_persons: + AddPersonToSlice.__call__(AddPersonToSlice(self.api), auth, new_person, self['slice_id']) + for stale_person in stale_persons: + DeletePersonFromSlice.__call__(DeletePersonFromSlice(self.api), auth, stale_person, self['slice_id']) + + def associate_nodes(self, auth, field, value): + """ + Adds nodes found in value list to this slice (using AddSliceToNodes). + Deletes nodes not found in value list from this slice (using DeleteSliceFromNodes). + """ + + from PLC.Nodes import Nodes + + assert 'node_ids' in self + assert 'slice_id' in self + assert isinstance(value, list) + + (node_ids, hostnames) = self.separate_types(value)[0:2] + + # Translate hostnames into node_ids + if hostnames: + nodes = Nodes(self.api, hostnames, ['node_id']).dict('node_id') + node_ids += nodes.keys() + + # Add new ids, remove stale ids + if self['node_ids'] != node_ids: + from PLC.Methods.AddSliceToNodes import AddSliceToNodes + from PLC.Methods.DeleteSliceFromNodes import DeleteSliceFromNodes + new_nodes = set(node_ids).difference(self['node_ids']) + stale_nodes = set(self['node_ids']).difference(node_ids) + + if new_nodes: + AddSliceToNodes.__call__(AddSliceToNodes(self.api), auth, self['slice_id'], list(new_nodes)) + if stale_nodes: + DeleteSliceFromNodes.__call__(DeleteSliceFromNodes(self.api), auth, self['slice_id'], list(stale_nodes)) + def associate_slice_attributes(self, auth, fields, value): + """ + Deletes slice_attribute_ids not found in value list (using DeleteSliceAttribute). + Adds slice_attributes if slice_fields w/o slice_id is found (using AddSliceAttribute). + Updates slice_attribute if slice_fields w/ slice_id is found (using UpdateSlceiAttribute). + """ + + assert 'slice_attribute_ids' in self + assert isinstance(value, list) + + (attribute_ids, blank, attributes) = self.separate_types(value) + + # There is no way to add attributes by id. They are + # associated with a slice when they are created. + # So we are only looking to delete here + if self['slice_attribute_ids'] != attribute_ids: + from PLC.Methods.DeleteSliceAttribute import DeleteSliceAttribute + stale_attributes = set(self['slice_attribute_ids']).difference(attribute_ids) + + for stale_attribute in stale_attributes: + DeleteSliceAttribute.__call__(DeleteSliceAttribute(self.api), auth, stale_attribute['slice_attribute_id']) + + # If dictionary exists, we are either adding new + # attributes or updating existing ones. + if attributes: + from PLC.Methods.AddSliceAttribute import AddSliceAttribute + from PLC.Methods.UpdateSliceAttribute import UpdateSliceAttribute + + added_attributes = filter(lambda x: 'slice_attribute_id' not in x, attributes) + updated_attributes = filter(lambda x: 'slice_attribute_id' in x, attributes) + + for added_attribute in added_attributes: + if 'attribute_type' in added_attribute: + type = added_attribute['attribute_type'] + elif 'attribute_type_id' in added_attribute: + type = added_attribute['attribute_type_id'] + else: + raise PLCInvalidArgument, "Must specify attribute_type or attribute_type_id" + + if 'value' in added_attribute: + value = added_attribute['value'] + else: + raise PLCInvalidArgument, "Must specify a value" + + if 'node_id' in added_attribute: + node_id = added_attribute['node_id'] + else: + node_id = None + + if 'nodegroup_id' in added_attribute: + nodegroup_id = added_attribute['nodegroup_id'] + else: + nodegroup_id = None + + AddSliceAttribute.__call__(AddSliceAttribute(self.api), auth, self['slice_id'], type, value, node_id, nodegroup_id) + for updated_attribute in updated_attributes: + attribute_id = updated_attribute.pop('slice_attribute_id') + if attribute_id not in self['slice_attribute_ids']: + raise PLCInvalidArgument, "Attribute doesnt belong to this slice" + else: + UpdateSliceAttribute.__call__(UpdateSliceAttribute(self.api), auth, attribute_id, updated_attribute) + def sync(self, commit = True): """ Add or update a slice. @@ -126,6 +254,7 @@ class Slice(Row): self['is_deleted'] = True self.sync(commit) + class Slices(Table): """ Representation of row(s) from the slices table in the @@ -151,16 +280,16 @@ class Slices(Table): ints = filter(lambda x: isinstance(x, (int, long)), slice_filter) strs = filter(lambda x: isinstance(x, StringTypes), slice_filter) slice_filter = Filter(Slice.fields, {'slice_id': ints, 'name': strs}) - sql += " AND (%s)" % slice_filter.sql(api, "OR") + sql += " AND (%s) %s" % slice_filter.sql(api, "OR") elif isinstance(slice_filter, dict): slice_filter = Filter(Slice.fields, slice_filter) - sql += " AND (%s)" % slice_filter.sql(api, "AND") - elif isinstance (slice_filter, StringTypes): + sql += " AND (%s) %s" % slice_filter.sql(api, "AND") + elif isinstance (slice_filter, StringTypes): slice_filter = Filter(Slice.fields, {'name':[slice_filter]}) - sql += " AND (%s)" % slice_filter.sql(api, "AND") + sql += " AND (%s) %s" % slice_filter.sql(api, "AND") elif isinstance (slice_filter, int): slice_filter = Filter(Slice.fields, {'slice_id':[slice_filter]}) - sql += " AND (%s)" % slice_filter.sql(api, "AND") + sql += " AND (%s) %s" % slice_filter.sql(api, "AND") else: raise PLCInvalidArgument, "Wrong slice filter %r"%slice_filter diff --git a/PLC/Table.py b/PLC/Table.py index 4e9ddabb..2362d61a 100644 --- a/PLC/Table.py +++ b/PLC/Table.py @@ -50,6 +50,35 @@ class Row(dict): if value is not None and hasattr(self, 'validate_' + key): validate = getattr(self, 'validate_' + key) self[key] = validate(value) + + def separate_types(self, items): + """ + Separate a list of different typed objects. + Return a list for each type (ints, strs and dicts) + """ + + if isinstance(items, (list, tuple, set)): + ints = filter(lambda x: isinstance(x, (int, long)), items) + strs = filter(lambda x: isinstance(x, StringTypes), items) + dicts = filter(lambda x: isinstance(x, dict), items) + return (ints, strs, dicts) + else: + raise PLCInvalidArgument, "Can only separate list types" + + + def associate(self, *args): + """ + Provides a means for high lvl api calls to associate objects + using low lvl calls. + """ + + if len(args) < 3: + raise PLCInvalidArgumentCount, "auth, field, value must be specified" + elif hasattr(self, 'associate_' + args[1]): + associate = getattr(self, 'associate_'+args[1]) + associate(*args) + else: + raise PLCInvalidArguemnt, "No such associate function associate_%s" % args[1] def validate_timestamp(self, timestamp, check_future = False): """ diff --git a/PLC/Test.py b/PLC/Test.py index addbafc8..48671194 100644 --- a/PLC/Test.py +++ b/PLC/Test.py @@ -5,7 +5,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: Test.py,v 1.3 2007/09/12 17:52:27 tmack Exp $ +# $Id: Test.py 5574 2007-10-25 20:33:17Z thierry $ # from pprint import pprint diff --git a/PLC/__init__.py b/PLC/__init__.py index 5d41de2e..d5ddda8a 100644 --- a/PLC/__init__.py +++ b/PLC/__init__.py @@ -1,7 +1,7 @@ all = """ -API -AddressTypes Addresses +AddressTypes +API Auth Boot BootStates @@ -14,33 +14,35 @@ Faults Filter GPG InitScripts -KeyTypes Keys +KeyTypes Messages Method NetworkMethods NetworkTypes NodeGroups -NodeNetworkSettingTypes NodeNetworkSettings +NodeNetworkSettingTypes NodeNetworks Nodes -PCUs -POD Parameter +PCUProtocolTypes +PCUs +PCUTypes Peers Persons +POD PostgreSQL PyCurl Roles +sendmail Sessions Shell Sites -SliceAttributeTypes SliceAttributes +SliceAttributeTypes SliceInstantiations Slices Table Test -sendmail """.split() -- 2.47.0