From 84d214e3c398bbb172e1a4a0adc22e57179d5954 Mon Sep 17 00:00:00 2001 From: Stephen Soltesz Date: Fri, 13 Nov 2009 22:33:07 +0000 Subject: [PATCH] add site_tags : GetSites() now returns 'site_tag_ids' attribute. added Add/Delete/Get/UpdateSiteTag*() methods added SiteTags.py to define the site tags table. Similar to the other Tag tables --- PLC/Legacy/__init__.py | 4 +- PLC/Methods/AddSiteTag.py | 89 ++++++++++++++++++++++++++++++++++++ PLC/Methods/DeleteSiteTag.py | 71 ++++++++++++++++++++++++++++ PLC/Methods/GetSiteTags.py | 45 ++++++++++++++++++ PLC/Methods/UpdateSiteTag.py | 68 +++++++++++++++++++++++++++ PLC/Methods/__init__.py | 56 ++++++++++++----------- PLC/SiteTags.py | 61 ++++++++++++++++++++++++ PLC/Sites.py | 16 +++++-- PLC/TagTypes.py | 2 +- PLC/__init__.py | 28 ++++++------ 10 files changed, 394 insertions(+), 46 deletions(-) create mode 100644 PLC/Methods/AddSiteTag.py create mode 100644 PLC/Methods/DeleteSiteTag.py create mode 100644 PLC/Methods/GetSiteTags.py create mode 100644 PLC/Methods/UpdateSiteTag.py create mode 100644 PLC/SiteTags.py diff --git a/PLC/Legacy/__init__.py b/PLC/Legacy/__init__.py index ead4e2a..64f72be 100644 --- a/PLC/Legacy/__init__.py +++ b/PLC/Legacy/__init__.py @@ -10,11 +10,11 @@ DeleteNodeNetworkSetting DeleteNodeNetworkSettingType DeleteSliceAttribute DeleteSliceAttributeType -GetNodeNetworkSettings GetNodeNetworkSettingTypes +GetNodeNetworkSettings GetNodeNetworks -GetSliceAttributes GetSliceAttributeTypes +GetSliceAttributes UpdateNodeNetwork UpdateNodeNetworkSetting UpdateNodeNetworkSettingType diff --git a/PLC/Methods/AddSiteTag.py b/PLC/Methods/AddSiteTag.py new file mode 100644 index 0000000..dda3f57 --- /dev/null +++ b/PLC/Methods/AddSiteTag.py @@ -0,0 +1,89 @@ +# $Id: AddSiteTag.py 14587 2009-07-19 13:18:50Z thierry $ +# $URL: http://svn.planet-lab.org/svn/PLCAPI/tags/PLCAPI-4.3-27/PLC/Methods/AddSiteTag.py $ +# +# Thierry Parmentelat - INRIA +# +# $Revision: 14587 $ +# +from PLC.Faults import * +from PLC.Method import Method +from PLC.Parameter import Parameter, Mixed +from PLC.Auth import Auth + +from PLC.TagTypes import TagType, TagTypes +from PLC.SiteTags import SiteTag, SiteTags +from PLC.Sites import Site, Sites + +from PLC.Nodes import Nodes +from PLC.Sites import Sites + +class AddSiteTag(Method): + """ + Sets the specified setting for the specified site + to the specified value. + + In general only tech(s), PI(s) and of course admin(s) are allowed to + do the change, but this is defined in the tag type object. + + Returns the new site_tag_id (> 0) if successful, faults + otherwise. + """ + + roles = ['admin', 'pi', 'tech', 'user'] + + accepts = [ + Auth(), + # no other way to refer to a site + SiteTag.fields['site_id'], + Mixed(TagType.fields['tag_type_id'], + TagType.fields['tagname']), + SiteTag.fields['value'], + ] + + returns = Parameter(int, 'New site_tag_id (> 0) if successful') + + object_type = 'Site' + + + def call(self, auth, site_id, tag_type_id_or_name, value): + sites = Sites(self.api, [site_id]) + if not sites: + raise PLCInvalidArgument, "No such site %r"%site_id + site = sites[0] + + tag_types = TagTypes(self.api, [tag_type_id_or_name]) + if not tag_types: + raise PLCInvalidArgument, "No such tag type %r"%tag_type_id_or_name + tag_type = tag_types[0] + + # checks for existence - does not allow several different settings + conflicts = SiteTags(self.api, + {'site_id':site['site_id'], + 'tag_type_id':tag_type['tag_type_id']}) + + if len(conflicts) : + raise PLCInvalidArgument, "Site %d already has setting %d"%(site['site_id'], + tag_type['tag_type_id']) + + # check permission : it not admin, is the user affiliated with the right site + if 'admin' not in self.caller['roles']: + # locate site + site = Sites (self.api, site_id)[0] + # check caller is affiliated with this site + if self.caller['person_id'] not in site['person_ids']: + raise PLCPermissionDenied, "Not a member of the hosting site %s"%site['abbreviated_site'] + + required_min_role = tag_type ['min_role_id'] + if required_min_role is not None and \ + min(self.caller['role_ids']) > required_min_role: + raise PLCPermissionDenied, "Not allowed to modify the specified site setting, requires role %d",required_min_role + + site_tag = SiteTag(self.api) + site_tag['site_id'] = site['site_id'] + site_tag['tag_type_id'] = tag_type['tag_type_id'] + site_tag['value'] = value + + site_tag.sync() + self.object_ids = [site_tag['site_tag_id']] + + return site_tag['site_tag_id'] diff --git a/PLC/Methods/DeleteSiteTag.py b/PLC/Methods/DeleteSiteTag.py new file mode 100644 index 0000000..f1e06aa --- /dev/null +++ b/PLC/Methods/DeleteSiteTag.py @@ -0,0 +1,71 @@ +# $Id: DeleteSiteTag.py 14587 2009-07-19 13:18:50Z thierry $ +# $URL: http://svn.planet-lab.org/svn/PLCAPI/tags/PLCAPI-4.3-27/PLC/Methods/DeleteSiteTag.py $ +# +# Thierry Parmentelat - INRIA +# +# $Revision: 14587 $ +# + +from PLC.Faults import * +from PLC.Method import Method +from PLC.Parameter import Parameter, Mixed +from PLC.Auth import Auth + +from PLC.SiteTags import SiteTag, SiteTags +from PLC.Sites import Site, Sites + +from PLC.Nodes import Node, Nodes +from PLC.Sites import Site, Sites + +class DeleteSiteTag(Method): + """ + Deletes the specified site setting + + Attributes may require the caller to have a particular role in order + to be deleted, depending on the related tag type. + Admins may delete attributes of any slice or sliver. + + Returns 1 if successful, faults otherwise. + """ + + roles = ['admin', 'pi', 'user'] + + accepts = [ + Auth(), + SiteTag.fields['site_tag_id'] + ] + + returns = Parameter(int, '1 if successful') + + object_type = 'Site' + + + def call(self, auth, site_tag_id): + site_tags = SiteTags(self.api, [site_tag_id]) + if not site_tags: + raise PLCInvalidArgument, "No such site tag %r"%site_tag_id + site_tag = site_tags[0] + + ### reproducing a check from UpdateSliceTag, looks dumb though + sites = Sites(self.api, [site_tag['site_id']]) + if not sites: + raise PLCInvalidArgument, "No such site %r"%site_tag['site_id'] + site = sites[0] + + assert site_tag['site_tag_id'] in site['site_tag_ids'] + + # check permission : it not admin, is the user affiliated with the right site + if 'admin' not in self.caller['roles']: + # check caller is affiliated with this site + if self.caller['person_id'] not in site['person_ids']: + raise PLCPermissionDenied, "Not a member of the hosting site %s"%site['abbreviated_site'] + + required_min_role = tag_type ['min_role_id'] + if required_min_role is not None and \ + min(self.caller['role_ids']) > required_min_role: + raise PLCPermissionDenied, "Not allowed to modify the specified site setting, requires role %d",required_min_role + + site_tag.delete() + self.object_ids = [site_tag['site_tag_id']] + + return 1 diff --git a/PLC/Methods/GetSiteTags.py b/PLC/Methods/GetSiteTags.py new file mode 100644 index 0000000..4663e8a --- /dev/null +++ b/PLC/Methods/GetSiteTags.py @@ -0,0 +1,45 @@ +# $Id: GetSiteTags.py 14587 2009-07-19 13:18:50Z thierry $ +# $URL: http://svn.planet-lab.org/svn/PLCAPI/tags/PLCAPI-4.3-27/PLC/Methods/GetSiteTags.py $ +# +# Thierry Parmentelat - INRIA +# +# $Revision: 14587 $ +# +from PLC.Faults import * +from PLC.Method import Method +from PLC.Parameter import Parameter, Mixed +from PLC.Filter import Filter +from PLC.Auth import Auth + +from PLC.SiteTags import SiteTag, SiteTags +from PLC.Sites import Site, Sites + +class GetSiteTags(Method): + """ + Returns an array of structs containing details about + sites and related settings. + + If site_tag_filter is specified and is an array of + site setting identifiers, only site settings matching + the filter will be returned. If return_fields is specified, only + the specified details will be returned. + """ + + roles = ['admin', 'pi', 'user', 'node'] + + accepts = [ + Auth(), + Mixed([SiteTag.fields['site_tag_id']], + Parameter(int,"Site setting id"), + Filter(SiteTag.fields)), + Parameter([str], "List of fields to return", nullok = True) + ] + + returns = [SiteTag.fields] + + + def call(self, auth, site_tag_filter = None, return_fields = None): + + site_tags = SiteTags(self.api, site_tag_filter, return_fields) + + return site_tags diff --git a/PLC/Methods/UpdateSiteTag.py b/PLC/Methods/UpdateSiteTag.py new file mode 100644 index 0000000..c7f63a3 --- /dev/null +++ b/PLC/Methods/UpdateSiteTag.py @@ -0,0 +1,68 @@ +# $Id: UpdateSiteTag.py 14587 2009-07-19 13:18:50Z thierry $ +# $URL: http://svn.planet-lab.org/svn/PLCAPI/tags/PLCAPI-4.3-27/PLC/Methods/UpdateSiteTag.py $ +# +# $Revision: 14587 $ +# + +from PLC.Faults import * +from PLC.Method import Method +from PLC.Parameter import Parameter, Mixed +from PLC.Auth import Auth + +from PLC.SiteTags import SiteTag, SiteTags +from PLC.Sites import Site, Sites + +from PLC.Nodes import Nodes +from PLC.Sites import Sites + +class UpdateSiteTag(Method): + """ + Updates the value of an existing site setting + + Access rights depend on the tag type. + + Returns 1 if successful, faults otherwise. + """ + + roles = ['admin', 'pi', 'tech', 'user'] + + accepts = [ + Auth(), + SiteTag.fields['site_tag_id'], + SiteTag.fields['value'] + ] + + returns = Parameter(int, '1 if successful') + + object_type = 'Site' + + def call(self, auth, site_tag_id, value): + site_tags = SiteTags(self.api, [site_tag_id]) + if not site_tags: + raise PLCInvalidArgument, "No such site setting %r"%site_tag_id + site_tag = site_tags[0] + + ### reproducing a check from UpdateSliceTag, looks dumb though + sites = Sites(self.api, [site_tag['site_id']]) + if not sites: + raise PLCInvalidArgument, "No such site %r"%site_tag['site_id'] + site = sites[0] + + assert site_tag['site_tag_id'] in site['site_tag_ids'] + + # check permission : it not admin, is the user affiliated with the right site + if 'admin' not in self.caller['roles']: + # check caller is affiliated with this site + if self.caller['person_id'] not in site['person_ids']: + raise PLCPermissionDenied, "Not a member of the hosting site %s"%site['abbreviated_site'] + + required_min_role = tag_type ['min_role_id'] + if required_min_role is not None and \ + min(self.caller['role_ids']) > required_min_role: + raise PLCPermissionDenied, "Not allowed to modify the specified site setting, requires role %d",required_min_role + + site_tag['value'] = value + site_tag.sync() + + self.object_ids = [site_tag['site_tag_id']] + return 1 diff --git a/PLC/Methods/__init__.py b/PLC/Methods/__init__.py index 5912fc1..50c1dea 100644 --- a/PLC/Methods/__init__.py +++ b/PLC/Methods/__init__.py @@ -4,8 +4,8 @@ AddAddressType AddAddressTypeToAddress AddBootState AddConfFile -AddConfFileToNodeGroup AddConfFileToNode +AddConfFileToNodeGroup AddIlink AddInitScript AddInterface @@ -14,26 +14,27 @@ AddKeyType AddMessage AddNetworkMethod AddNetworkType -AddNodeGroup AddNode +AddNodeGroup AddNodeTag AddNodeToPCU AddNodeType -AddPCUProtocolType AddPCU +AddPCUProtocolType AddPCUType AddPeer -AddPersonKey AddPerson +AddPersonKey AddPersonToSite AddPersonToSlice AddRole AddRoleToPerson AddSession -AddSiteAddress AddSite -AddSliceInstantiation +AddSiteAddress +AddSiteTag AddSlice +AddSliceInstantiation AddSliceTag AddSliceToNodes AddSliceToNodesWhitelist @@ -46,12 +47,12 @@ BootGetNodeDetails BootNotifyOwners BootUpdateNode DeleteAddress -DeleteAddressTypeFromAddress DeleteAddressType +DeleteAddressTypeFromAddress DeleteBootState -DeleteConfFileFromNodeGroup -DeleteConfFileFromNode DeleteConfFile +DeleteConfFileFromNode +DeleteConfFileFromNodeGroup DeleteEmulationLink DeleteIlink DeleteInitScript @@ -62,31 +63,32 @@ DeleteKeyType DeleteMessage DeleteNetworkMethod DeleteNetworkType +DeleteNode DeleteNodeFromPCU DeleteNodeGroup -DeleteNode DeleteNodeTag DeleteNodeType -DeletePCUProtocolType DeletePCU +DeletePCUProtocolType DeletePCUType DeletePeer +DeletePerson DeletePersonFromSite DeletePersonFromSlice -DeletePerson -DeleteRoleFromPerson DeleteRole +DeleteRoleFromPerson DeleteSession DeleteSite +DeleteSiteTag +DeleteSlice DeleteSliceFromNodes DeleteSliceFromNodesWhitelist DeleteSliceInstantiation -DeleteSlice DeleteSliceTag DeleteTagType GenerateNodeConfFile -GetAddresses GetAddressTypes +GetAddresses GetBootMedium GetBootStates GetConfFiles @@ -94,20 +96,20 @@ GetEventObjects GetEvents GetIlinks GetInitScripts -GetInterfaces GetInterfaceTags -GetKeys +GetInterfaces GetKeyTypes +GetKeys GetMessages GetNetworkMethods GetNetworkTypes GetNodeGroups -GetNodes GetNodeTags GetNodeTypes +GetNodes GetPCUProtocolTypes -GetPCUs GetPCUTypes +GetPCUs GetPeerData GetPeerName GetPeers @@ -116,12 +118,13 @@ GetPlcRelease GetRoles GetSession GetSessions +GetSiteTags GetSites GetSliceInstantiations GetSliceKeys -GetSlices GetSliceTags GetSliceTicket +GetSlices GetSlivers GetTagTypes GetWhitelist @@ -150,10 +153,6 @@ SliceUpdate SliceUserAdd SliceUserDel SliceUsersList -system.listMethods -system.methodHelp -system.methodSignature -system.multicall UnBindObjectFromPeer UpdateAddress UpdateAddressType @@ -165,17 +164,22 @@ UpdateInterface UpdateInterfaceTag UpdateKey UpdateMessage -UpdateNodeGroup UpdateNode +UpdateNodeGroup UpdateNodeTag -UpdatePCUProtocolType UpdatePCU +UpdatePCUProtocolType UpdatePCUType UpdatePeer UpdatePerson UpdateSite +UpdateSiteTag UpdateSlice UpdateSliceTag UpdateTagType VerifyPerson +system.listMethods +system.methodHelp +system.methodSignature +system.multicall """.split() diff --git a/PLC/SiteTags.py b/PLC/SiteTags.py new file mode 100644 index 0000000..8ccf5bb --- /dev/null +++ b/PLC/SiteTags.py @@ -0,0 +1,61 @@ +# $Id: SiteTags.py 14587 2009-07-19 13:18:50Z thierry $ +# $URL: http://svn.planet-lab.org/svn/PLCAPI/tags/PLCAPI-4.3-27/PLC/SiteTags.py $ +# +# Thierry Parmentelat - INRIA +# +# $Revision: 14587 $ +# +from PLC.Faults import * +from PLC.Parameter import Parameter +from PLC.Filter import Filter +from PLC.Table import Row, Table +from PLC.TagTypes import TagType, TagTypes +from PLC.Sites import Site + +class SiteTag(Row): + """ + Representation of a row in the site_tag. + To use, instantiate with a dict of values. + """ + + table_name = 'site_tag' + primary_key = 'site_tag_id' + fields = { + 'site_tag_id': Parameter(int, "Site setting identifier"), + 'site_id': Site.fields['site_id'], + 'login_base': Site.fields['login_base'], + 'tag_type_id': TagType.fields['tag_type_id'], + 'tagname': TagType.fields['tagname'], + 'description': TagType.fields['description'], + 'category': TagType.fields['category'], + 'min_role_id': TagType.fields['min_role_id'], + 'value': Parameter(str, "Site setting value"), + ### relations + + } + +class SiteTags(Table): + """ + Representation of row(s) from the site_tag table in the + database. + """ + + def __init__(self, api, site_tag_filter = None, columns = None): + Table.__init__(self, api, SiteTag, columns) + + sql = "SELECT %s FROM view_site_tags WHERE True" % \ + ", ".join(self.columns) + + if site_tag_filter is not None: + if isinstance(site_tag_filter, (list, tuple, set)): + site_tag_filter = Filter(SiteTag.fields, {'site_tag_id': site_tag_filter}) + elif isinstance(site_tag_filter, dict): + site_tag_filter = Filter(SiteTag.fields, site_tag_filter) + elif isinstance(site_tag_filter, int): + site_tag_filter = Filter(SiteTag.fields, {'site_tag_id': [site_tag_filter]}) + else: + raise PLCInvalidArgument, "Wrong site setting filter %r"%site_tag_filter + sql += " AND (%s) %s" % site_tag_filter.sql(api) + + + self.selectall(sql) diff --git a/PLC/Sites.py b/PLC/Sites.py index d31f4ea..ef9f02a 100644 --- a/PLC/Sites.py +++ b/PLC/Sites.py @@ -45,6 +45,7 @@ class Site(Row): 'node_ids': Parameter([int], "List of site node identifiers"), 'peer_id': Parameter(int, "Peer to which this site belongs", nullok = True), 'peer_site_id': Parameter(int, "Foreign site identifier at peer", nullok = True), + 'site_tag_ids' : Parameter ([int], "List of tags attached to this site"), 'ext_consortium_id': Parameter(int, "external consortium id", nullok = True) } related_fields = { @@ -53,6 +54,10 @@ class Site(Row): 'addresses': [Mixed(Parameter(int, "Address identifer"), Filter(Address.fields))] } + view_tags_name = "view_site_tags" + # tags are used by the Add/Get/Update methods to expose tags + # this is initialized here and updated by the accessors factory + tags = { } def validate_name(self, name): if not len(name): @@ -238,9 +243,14 @@ class Sites(Table): def __init__(self, api, site_filter = None, columns = None): Table.__init__(self, api, Site, columns) - - sql = "SELECT %s FROM view_sites WHERE deleted IS False" % \ - ", ".join(self.columns) + + view = "view_sites" + for tagname in self.tag_columns: + view= "%s left join %s using (%s)"%(view,Site.tagvalue_view_name(tagname), + Site.primary_key) + + sql = "SELECT %s FROM %s WHERE deleted IS False" % \ + (", ".join(self.columns.keys()+self.tag_columns.keys()),view) if site_filter is not None: if isinstance(site_filter, (list, tuple, set)): diff --git a/PLC/TagTypes.py b/PLC/TagTypes.py index 48a9f19..39306f5 100644 --- a/PLC/TagTypes.py +++ b/PLC/TagTypes.py @@ -23,7 +23,7 @@ class TagType (Row): table_name = 'tag_types' primary_key = 'tag_type_id' - join_tables = ['node_tag', 'interface_tag', 'slice_tag' ] + join_tables = ['node_tag', 'interface_tag', 'slice_tag', 'site_tag' ] fields = { 'tag_type_id': Parameter(int, "Node tag type identifier"), 'tagname': Parameter(str, "Node tag type name", max = 100), diff --git a/PLC/__init__.py b/PLC/__init__.py index 73385d7..5ee17c4 100644 --- a/PLC/__init__.py +++ b/PLC/__init__.py @@ -1,8 +1,8 @@ ## Please use make index to update this file all = """ -Addresses -AddressTypes API +AddressTypes +Addresses Auth Boot BootStates @@ -16,42 +16,42 @@ Filter GPG Ilinks InitScripts -Interfaces InterfaceTags -Keys +Interfaces KeyTypes +Keys Messages Method NetworkMethods NetworkTypes NodeGroups -Nodes NodeTags NodeTypes -Parameter +Nodes PCUProtocolTypes -PCUs PCUTypes +PCUs +POD +Parameter Peers Persons -POD PostgreSQL PyCurl Roles -sendmail Sessions -SFA Shell +SiteTags Sites SliceInstantiations -Slices SliceTags +Slices Table TagTypes -v42LegacyNodeNetworkSettings +sendmail +v42Legacy v42LegacyNodeNetworkSettingTypes +v42LegacyNodeNetworkSettings v42LegacyNodeNetworks -v42Legacy -v42LegacySliceAttributes v42LegacySliceAttributeTypes +v42LegacySliceAttributes """.split() -- 2.43.0