From c4fb0b1d1fabecb314cc4d5db802ac9c6ffe3708 Mon Sep 17 00:00:00 2001 From: Thierry Parmentelat Date: Sun, 19 Jul 2009 07:55:00 +0000 Subject: [PATCH] revised type-checking on taggable classes - previous code would reject any tag --- PLC/Methods/AddInterface.py | 10 ++++++---- PLC/Methods/AddNode.py | 7 ++++--- PLC/Methods/AddSlice.py | 7 ++++--- PLC/Methods/GetNodes.py | 12 +++++++++--- PLC/Methods/UpdateInterface.py | 9 +++++---- PLC/Methods/UpdateNode.py | 21 ++++++++++++--------- PLC/Methods/UpdateSlice.py | 14 ++++++++------ PLC/Table.py | 20 ++++++++++---------- 8 files changed, 58 insertions(+), 42 deletions(-) diff --git a/PLC/Methods/AddInterface.py b/PLC/Methods/AddInterface.py index 662d7fd..69e92ec 100644 --- a/PLC/Methods/AddInterface.py +++ b/PLC/Methods/AddInterface.py @@ -12,7 +12,7 @@ from PLC.InterfaceTags import InterfaceTags from PLC.Methods.AddInterfaceTag import AddInterfaceTag from PLC.Methods.UpdateInterfaceTag import UpdateInterfaceTag -can_update = ['interface_id', 'node_id'] +cannot_update = ['interface_id', 'node_id'] class AddInterface(Method): """ @@ -33,7 +33,8 @@ class AddInterface(Method): roles = ['admin', 'pi', 'tech'] - accepted_fields = Row.accepted_fields(can_update, [Interface.fields,Interface.tags], exclude=True) + accepted_fields = Row.accepted_fields(cannot_update, Interface.fields, exclude=True) + accepted_fields.update(Interface.tags) accepts = [ Auth(), @@ -47,9 +48,10 @@ class AddInterface(Method): def call(self, auth, node_id_or_hostname, interface_fields): - interface_fields = Row.check_fields (interface_fields, self.accepted_fields) - [native,tags,rejected]=Row.split_fields(interface_fields,[Interface.fields,Interface.tags]) + + # type checking + native = Row.check_fields (native, self.accepted_fields) if rejected: raise PLCInvalidArgument, "Cannot add Interface with column(s) %r"%rejected diff --git a/PLC/Methods/AddNode.py b/PLC/Methods/AddNode.py index b722585..d25e8b2 100644 --- a/PLC/Methods/AddNode.py +++ b/PLC/Methods/AddNode.py @@ -27,7 +27,8 @@ class AddNode(Method): roles = ['admin', 'pi', 'tech'] - accepted_fields = Row.accepted_fields(can_update, [Node.fields,Node.tags]) + accepted_fields = Row.accepted_fields(can_update,Node.fields) + accepted_fields.update(Node.tags) accepts = [ Auth(), @@ -40,10 +41,10 @@ class AddNode(Method): def call(self, auth, site_id_or_login_base, node_fields): - node_fields = Row.check_fields (node_fields, self.accepted_fields) - [native,tags,rejected]=Row.split_fields(node_fields,[Node.fields,Node.tags]) + # type checking + native = Row.check_fields (native, self.accepted_fields) if rejected: raise PLCInvalidArgument, "Cannot add Node with column(s) %r"%rejected diff --git a/PLC/Methods/AddSlice.py b/PLC/Methods/AddSlice.py index 3e2a89c..a29b41f 100644 --- a/PLC/Methods/AddSlice.py +++ b/PLC/Methods/AddSlice.py @@ -35,7 +35,8 @@ class AddSlice(Method): roles = ['admin', 'pi'] - accepted_fields = Row.accepted_fields(can_update, [Slice.fields,Slice.tags]) + accepted_fields = Row.accepted_fields(can_update, Slice.fields) + accepted_fields.update(Slice.tags) accepts = [ Auth(), @@ -46,10 +47,10 @@ class AddSlice(Method): def call(self, auth, slice_fields): - slice_fields = Row.check_fields (slice_fields, self.accepted_fields) - [native,tags,rejected]=Row.split_fields(slice_fields,[Slice.fields,Slice.tags]) + # type checking + native = Row.check_fields (native, self.accepted_fields) if rejected: raise PLCInvalidArgument, "Cannot add Slice with column(s) %r"%rejected diff --git a/PLC/Methods/GetNodes.py b/PLC/Methods/GetNodes.py index bc7dc7e..a5df248 100644 --- a/PLC/Methods/GetNodes.py +++ b/PLC/Methods/GetNodes.py @@ -7,13 +7,19 @@ from PLC.Nodes import Node, Nodes from PLC.Persons import Person, Persons from PLC.Auth import Auth +admin_only = ['key', 'session', 'boot_nonce' ] + class v43GetNodes(Method): """ Returns an array of structs containing details about nodes. If node_filter is specified and is an array of node identifiers or hostnames, or a struct of node attributes, only nodes matching the - filter will be returned. If return_fields is specified, only the - specified details will be returned. + filter will be returned. + + If return_fields is specified, only the specified details will be + returned. NOTE that if return_fields is unspecified, the complete + set of native fields are returned, which DOES NOT include tags at + this time. Some fields may only be viewed by admins. """ @@ -71,7 +77,7 @@ class v43GetNodes(Method): # remove remaining admin only fields for node in nodes: - for field in ['boot_nonce', 'key', 'session', 'root_person_ids']: + for field in admin_only: if field in node: del node[field] diff --git a/PLC/Methods/UpdateInterface.py b/PLC/Methods/UpdateInterface.py index 48f3822..64b37d9 100644 --- a/PLC/Methods/UpdateInterface.py +++ b/PLC/Methods/UpdateInterface.py @@ -12,7 +12,7 @@ from PLC.Interfaces import Interface, Interfaces from PLC.Methods.AddInterfaceTag import AddInterfaceTag from PLC.Methods.UpdateInterfaceTag import UpdateInterfaceTag -can_update = ['interface_id','node_id'] +cannot_update = ['interface_id','node_id'] class UpdateInterface(Method): """ @@ -31,7 +31,8 @@ class UpdateInterface(Method): roles = ['admin', 'pi', 'tech'] - accepted_fields = Row.accepted_fields(can_update, [Interface.fields,Interface.tags],exclude=True) + accepted_fields = Row.accepted_fields(cannot_update, Interface.fields,exclude=True) + accepted_fields.update(Interface.tags) accepts = [ Auth(), @@ -43,10 +44,10 @@ class UpdateInterface(Method): def call(self, auth, interface_id, interface_fields): - interface_fields = Row.check_fields (interface_fields, self.accepted_fields) - [native,tags,rejected] = Row.split_fields(interface_fields,[Interface.fields,Interface.tags]) + # type checking + native= Row.check_fields (native, self.accepted_fields) if rejected: raise PLCInvalidArgument, "Cannot update Interface column(s) %r"%rejected diff --git a/PLC/Methods/UpdateNode.py b/PLC/Methods/UpdateNode.py index 6f60a46..1cf7a47 100644 --- a/PLC/Methods/UpdateNode.py +++ b/PLC/Methods/UpdateNode.py @@ -11,8 +11,8 @@ from PLC.NodeTags import NodeTags from PLC.Methods.AddNodeTag import AddNodeTag from PLC.Methods.UpdateNodeTag import UpdateNodeTag -can_update = ['hostname', 'boot_state', 'model', 'version','key', 'session', 'boot_nonce', 'site_id'] + \ - Node.related_fields.keys() +admin_only = [ 'key', 'session', 'boot_nonce', 'site_id'] +can_update = ['hostname', 'boot_state', 'model', 'version'] + admin_only class UpdateNode(Method): """ @@ -27,7 +27,10 @@ class UpdateNode(Method): roles = ['admin', 'pi', 'tech'] - accepted_fields = Row.accepted_fields(can_update,[Node.fields,Node.related_fields,Node.tags]) + accepted_fields = Row.accepted_fields(can_update,Node.fields) + # xxx check the related_fields feature + accepted_fields.update(Node.related_fields) + accepted_fields.update(Node.tags) accepts = [ Auth(), @@ -40,17 +43,20 @@ class UpdateNode(Method): def call(self, auth, node_id_or_hostname, node_fields): - node_fields = Row.check_fields (node_fields, self.accepted_fields) - # split provided fields [native,related,tags,rejected] = Row.split_fields(node_fields,[Node.fields,Node.related_fields,Node.tags]) + # type checking + native = Row.check_fields (native, self.accepted_fields) if rejected: raise PLCInvalidArgument, "Cannot update Node column(s) %r"%rejected + # Authenticated function + assert self.caller is not None + # Remove admin only fields if 'admin' not in self.caller['roles']: - for key in 'key', 'session', 'boot_nonce', 'site_id': + for key in admin_only: if native.has_key(key): del native[key] @@ -63,9 +69,6 @@ class UpdateNode(Method): if node['peer_id'] is not None: raise PLCInvalidArgument, "Not a local node %r"%node_id_or_hostname - # Authenticated function - assert self.caller is not None - # If we are not an admin, make sure that the caller is a # member of the site at which the node is located. if 'admin' not in self.caller['roles']: diff --git a/PLC/Methods/UpdateSlice.py b/PLC/Methods/UpdateSlice.py index bc28a55..333bac1 100644 --- a/PLC/Methods/UpdateSlice.py +++ b/PLC/Methods/UpdateSlice.py @@ -14,8 +14,7 @@ from PLC.SliceTags import SliceTags from PLC.Methods.AddSliceTag import AddSliceTag from PLC.Methods.UpdateSliceTag import UpdateSliceTag -can_update = ['instantiation', 'url', 'description', 'max_nodes', 'expires'] + \ - Slice.related_fields.keys() +can_update = ['instantiation', 'url', 'description', 'max_nodes', 'expires'] class UpdateSlice(Method): """ @@ -35,7 +34,10 @@ class UpdateSlice(Method): roles = ['admin', 'pi', 'user'] - accepted_fields = Row.accepted_fields(can_update, [Slice.fields,Slice.related_fields,Slice.tags]) + accepted_fields = Row.accepted_fields(can_update, Slice.fields) + # xxx check the related_fields feature + accepted_fields.update(Slice.related_fields) + accepted_fields.update(Slice.tags) accepts = [ Auth(), @@ -48,11 +50,11 @@ class UpdateSlice(Method): def call(self, auth, slice_id_or_name, slice_fields): - slice_fields = Row.check_fields (slice_fields, self.accepted_fields) - # split provided fields [native,related,tags,rejected] = Row.split_fields(slice_fields,[Slice.fields,Slice.related_fields,Slice.tags]) - + + # type checking + native = Row.check_fields (native, self.accepted_fields) if rejected: raise PLCInvalidArgument, "Cannot update Slice column(s) %r"%rejected diff --git a/PLC/Table.py b/PLC/Table.py index fdd755e..e56f316 100644 --- a/PLC/Table.py +++ b/PLC/Table.py @@ -228,8 +228,8 @@ class Row(dict): return dict ( [ (key,value) for (key,value) in obj.iteritems() if key in self.tags and Row.is_writable(key,value,self.tags) ] ) - # takes in input a list of columns, returns 2 dicts and one list - # fields, tags, rejected + # takes as input a list of columns, sort native fields from tags + # returns 2 dicts and one list : fields, tags, rejected @classmethod def parse_columns (cls, columns): (fields,tags,rejected)=({},{},[]) @@ -239,20 +239,20 @@ class Row(dict): else: rejected.append(column) return (fields,tags,rejected) - # compute the accepts part of an update method from a list of column names, and a (list of) fields dict + # compute the 'accepts' part of a method, from a list of column names, and a fields dict # use exclude=True to exclude the column names instead + # typically accepted_fields (Node.fields,['hostname','model',...]) @staticmethod - def accepted_fields (update_columns, fields, exclude=False): - if not isinstance(fields,list): fields = [fields] + def accepted_fields (update_columns, fields_dict, exclude=False): result={} - for fields_dict in fields: - for (k,v) in fields_dict.iteritems(): - if (not exclude and k in update_columns) or (exclude and k not in update_columns): - result[k]=v + for (k,v) in fields_dict.iteritems(): + if (not exclude and k in update_columns) or (exclude and k not in update_columns): + result[k]=v return result # filter out user-provided fields that are not part of the declared acceptance list - # this could maybe have been integrated in split_fields, but for simplicity we keep it aside + # keep it separate from split_fields for simplicity + # typically check_fields (,{'hostname':Parameter(str,...),'model':Parameter(..)...}) @staticmethod def check_fields (user_dict, accepted_fields): # avoid the simple, but silent, version -- 2.43.0