GetBootMedium: split former option systemd-debug in 2 parts: systemd-console and...
[plcapi.git] / PLC / Peers.py
index 21c9dfd..c24f925 100644 (file)
@@ -1,77 +1,82 @@
 #
 # Thierry Parmentelat - INRIA
 #
 # Thierry Parmentelat - INRIA
-# 
+#
 
 import re
 
 import re
-from types import StringTypes
-from urlparse import urlparse
+import traceback
+from urllib.parse import urlparse
 
 
+import PLC.Auth
+from PLC.Logger import logger
 from PLC.Faults import *
 from PLC.Faults import *
+from PLC.Namespace import hostname_to_hrn
 from PLC.Parameter import Parameter, Mixed
 from PLC.Filter import Filter
 from PLC.Table import Row, Table
 from PLC.Parameter import Parameter, Mixed
 from PLC.Filter import Filter
 from PLC.Table import Row, Table
-import PLC.Auth
-
 from PLC.Sites import Site, Sites
 from PLC.Persons import Person, Persons
 from PLC.Keys import Key, Keys
 from PLC.Nodes import Node, Nodes
 from PLC.Sites import Site, Sites
 from PLC.Persons import Person, Persons
 from PLC.Keys import Key, Keys
 from PLC.Nodes import Node, Nodes
-from PLC.SliceAttributeTypes import SliceAttributeType, SliceAttributeTypes
-from PLC.SliceAttributes import SliceAttribute, SliceAttributes
+from PLC.TagTypes import TagType, TagTypes
+from PLC.NodeTags import NodeTag, NodeTags
+from PLC.SliceTags import SliceTag, SliceTags
 from PLC.Slices import Slice, Slices
 
 class Peer(Row):
     """
 from PLC.Slices import Slice, Slices
 
 class Peer(Row):
     """
-    Stores the list of peering PLCs in the peers table. 
+    Stores the list of peering PLCs in the peers table.
     See the Row class for more details
     """
 
     table_name = 'peers'
     primary_key = 'peer_id'
     See the Row class for more details
     """
 
     table_name = 'peers'
     primary_key = 'peer_id'
-    join_tables = ['peer_site', 'peer_person', 'peer_key', 'peer_node',
-                   'peer_slice_attribute_type', 'peer_slice_attribute', 'peer_slice']
+    join_tables = ['peer_site', 'peer_person', 'peer_key', 'peer_node', 'peer_slice']
     fields = {
     fields = {
-       'peer_id': Parameter (int, "Peer identifier"),
-       'peername': Parameter (str, "Peer name"),
-       'peer_url': Parameter (str, "Peer API URL"),
-       'key': Parameter(str, "Peer GPG public key"),
-       'cacert': Parameter(str, "Peer SSL public certificate"),
+        'peer_id': Parameter (int, "Peer identifier"),
+        'peername': Parameter (str, "Peer name"),
+        'peer_url': Parameter (str, "Peer API URL"),
+        'key': Parameter(str, "Peer GPG public key"),
+        'cacert': Parameter(str, "Peer SSL public certificate"),
+        'shortname' : Parameter(str, "Peer short name"),
+        'hrn_root' : Parameter(str, "Root of this peer in a hierarchical naming space"),
         ### cross refs
         'site_ids': Parameter([int], "List of sites for which this peer is authoritative"),
         'person_ids': Parameter([int], "List of users for which this peer is authoritative"),
         'key_ids': Parameter([int], "List of keys for which this peer is authoritative"),
         'node_ids': Parameter([int], "List of nodes for which this peer is authoritative"),
         'slice_ids': Parameter([int], "List of slices for which this peer is authoritative"),
         ### cross refs
         'site_ids': Parameter([int], "List of sites for which this peer is authoritative"),
         'person_ids': Parameter([int], "List of users for which this peer is authoritative"),
         'key_ids': Parameter([int], "List of keys for which this peer is authoritative"),
         'node_ids': Parameter([int], "List of nodes for which this peer is authoritative"),
         'slice_ids': Parameter([int], "List of slices for which this peer is authoritative"),
-       }
+        }
 
     def validate_peername(self, peername):
         if not len(peername):
 
     def validate_peername(self, peername):
         if not len(peername):
-            raise PLCInvalidArgument, "Peer name must be specified"
+            raise PLCInvalidArgument("Peer name must be specified")
 
         conflicts = Peers(self.api, [peername])
         for peer in conflicts:
             if 'peer_id' not in self or self['peer_id'] != peer['peer_id']:
 
         conflicts = Peers(self.api, [peername])
         for peer in conflicts:
             if 'peer_id' not in self or self['peer_id'] != peer['peer_id']:
-                raise PLCInvalidArgument, "Peer name already in use"
+                raise PLCInvalidArgument("Peer name already in use")
 
         return peername
 
     def validate_peer_url(self, url):
 
         return peername
 
     def validate_peer_url(self, url):
-       """
-       Validate URL. Must be HTTPS.
-       """
+        """
+        Validate URL. Must be HTTPS.
+        """
 
         (scheme, netloc, path, params, query, fragment) = urlparse(url)
         if scheme != "https":
 
         (scheme, netloc, path, params, query, fragment) = urlparse(url)
         if scheme != "https":
-            raise PLCInvalidArgument, "Peer URL scheme must be https"
+            raise PLCInvalidArgument("Peer URL scheme must be https")
+        if path[-1] != '/':
+            raise PLCInvalidArgument("Peer URL should end with /")
 
 
-       return url
+        return url
 
     def delete(self, commit = True):
 
     def delete(self, commit = True):
-       """
-       Deletes this peer and all related entities.
-       """
+        """
+        Deletes this peer and all related entities.
+        """
 
 
-       assert 'peer_id' in self
+        assert 'peer_id' in self
 
         # Remove all related entities
         for obj in \
 
         # Remove all related entities
         for obj in \
@@ -84,8 +89,8 @@ class Peer(Row):
             obj.delete(commit = False)
 
         # Mark as deleted
             obj.delete(commit = False)
 
         # Mark as deleted
-       self['deleted'] = True
-       self.sync(commit)
+        self['deleted'] = True
+        self.sync(commit)
 
     def add_site(self, site, peer_site_id, commit = True):
         """
 
     def add_site(self, site, peer_site_id, commit = True):
         """
@@ -99,6 +104,14 @@ class Peer(Row):
              'peer_site_id': peer_site_id},
             commit = commit)
 
              'peer_site_id': peer_site_id},
             commit = commit)
 
+    def remove_site(self, site, commit = True):
+        """
+        Unassociate a site with this peer.
+        """
+
+        remove = Row.remove_object(Site, 'peer_site')
+        remove(self, site, commit)
+
     def add_person(self, person, peer_person_id, commit = True):
         """
         Associate a local user entry with this peer.
     def add_person(self, person, peer_person_id, commit = True):
         """
         Associate a local user entry with this peer.
@@ -111,6 +124,14 @@ class Peer(Row):
              'peer_person_id': peer_person_id},
             commit = commit)
 
              'peer_person_id': peer_person_id},
             commit = commit)
 
+    def remove_person(self, person, commit = True):
+        """
+        Unassociate a site with this peer.
+        """
+
+        remove = Row.remove_object(Person, 'peer_person')
+        remove(self, person, commit)
+
     def add_key(self, key, peer_key_id, commit = True):
         """
         Associate a local key entry with this peer.
     def add_key(self, key, peer_key_id, commit = True):
         """
         Associate a local key entry with this peer.
@@ -123,6 +144,14 @@ class Peer(Row):
              'peer_key_id': peer_key_id},
             commit = commit)
 
              'peer_key_id': peer_key_id},
             commit = commit)
 
+    def remove_key(self, key, commit = True):
+        """
+        Unassociate a key with this peer.
+        """
+
+        remove = Row.remove_object(Key, 'peer_key')
+        remove(self, key, commit)
+
     def add_node(self, node, peer_node_id, commit = True):
         """
         Associate a local node entry with this peer.
     def add_node(self, node, peer_node_id, commit = True):
         """
         Associate a local node entry with this peer.
@@ -135,6 +164,34 @@ class Peer(Row):
              'peer_node_id': peer_node_id},
             commit = commit)
 
              'peer_node_id': peer_node_id},
             commit = commit)
 
+        sites = Sites(self.api, node['site_id'], ['login_base'])
+        site = sites[0]
+        login_base = site['login_base']
+        try:
+            # attempt to manually update the 'hrn' tag with the remote prefix
+            hrn_root = self['hrn_root']
+            hrn = hostname_to_hrn(hrn_root, login_base, node['hostname'])
+            tags = {'hrn': hrn}
+            Node(self.api, node).update_tags(tags)
+        except:
+            logger.exception("Could not find out hrn on hostname=%s"%node['hostname'])
+
+    def remove_node(self, node, commit = True):
+        """
+        Unassociate a node with this peer.
+        """
+
+        remove = Row.remove_object(Node, 'peer_node')
+        remove(self, node, commit)
+        # attempt to manually update the 'hrn' tag now that the node is local
+        root_auth = self.api.config.PLC_HRN_ROOT
+        sites = Sites(self.api, node['site_id'], ['login_base'])
+        site = sites[0]
+        login_base = site['login_base']
+        hrn = hostname_to_hrn(root_auth, login_base, node['hostname'])
+        tags = {'hrn': hrn}
+        Node(self.api, node).update_tags(tags)
+
     def add_slice(self, slice, peer_slice_id, commit = True):
         """
         Associate a local slice entry with this peer.
     def add_slice(self, slice, peer_slice_id, commit = True):
         """
         Associate a local slice entry with this peer.
@@ -147,14 +204,22 @@ class Peer(Row):
              'peer_slice_id': peer_slice_id},
             commit = commit)
 
              'peer_slice_id': peer_slice_id},
             commit = commit)
 
+    def remove_slice(self, slice, commit = True):
+        """
+        Unassociate a slice with this peer.
+        """
+
+        remove = Row.remove_object(Slice, 'peer_slice')
+        remove(self, slice, commit)
+
     def connect(self, **kwds):
         """
         Connect to this peer via XML-RPC.
         """
 
     def connect(self, **kwds):
         """
         Connect to this peer via XML-RPC.
         """
 
-        import xmlrpclib
+        import xmlrpc.client
         from PLC.PyCurl import PyCurlTransport
         from PLC.PyCurl import PyCurlTransport
-        self.server = xmlrpclib.ServerProxy(self['peer_url'],
+        self.server = xmlrpc.client.ServerProxy(self['peer_url'],
                                             PyCurlTransport(self['peer_url'], self['cacert']),
                                             allow_none = 1, **kwds)
 
                                             PyCurlTransport(self['peer_url'], self['cacert']),
                                             allow_none = 1, **kwds)
 
@@ -166,9 +231,10 @@ class Peer(Row):
 
         def wrapper(*args, **kwds):
             from PLC.GPG import gpg_sign
 
         def wrapper(*args, **kwds):
             from PLC.GPG import gpg_sign
-            signature = gpg_sign(methodname, args,
+            signature = gpg_sign(args,
                                  self.api.config.PLC_ROOT_GPG_KEY,
                                  self.api.config.PLC_ROOT_GPG_KEY,
-                                 self.api.config.PLC_ROOT_GPG_KEY_PUB)
+                                 self.api.config.PLC_ROOT_GPG_KEY_PUB,
+                                 methodname)
 
             auth = {'AuthMethod': "gpg",
                     'name': self.api.config.PLC_NAME,
 
             auth = {'AuthMethod': "gpg",
                     'name': self.api.config.PLC_NAME,
@@ -198,37 +264,45 @@ class Peer(Row):
             if api_function.accepts and \
                (isinstance(api_function.accepts[0], PLC.Auth.Auth) or \
                 (isinstance(api_function.accepts[0], Mixed) and \
             if api_function.accepts and \
                (isinstance(api_function.accepts[0], PLC.Auth.Auth) or \
                 (isinstance(api_function.accepts[0], Mixed) and \
-                 filter(lambda param: isinstance(param, Auth), api_function.accepts[0]))):
+                 [param for param in api_function.accepts[0] if isinstance(param, Auth)])):
                 function = getattr(self.server, methodname)
                 return self.add_auth(function, methodname)
                 function = getattr(self.server, methodname)
                 return self.add_auth(function, methodname)
-        except Exception, err:
+        except Exception as err:
             pass
 
         if hasattr(self, attr):
             return getattr(self, attr)
         else:
             pass
 
         if hasattr(self, attr):
             return getattr(self, attr)
         else:
-            raise AttributeError, "type object 'Peer' has no attribute '%s'" % attr
+            raise AttributeError("type object 'Peer' has no attribute '%s'" % attr)
 
 class Peers (Table):
 
 class Peers (Table):
-    """ 
+    """
     Maps to the peers table in the database
     """
     Maps to the peers table in the database
     """
-    
+
     def __init__ (self, api, peer_filter = None, columns = None):
         Table.__init__(self, api, Peer, columns)
 
     def __init__ (self, api, peer_filter = None, columns = None):
         Table.__init__(self, api, Peer, columns)
 
-       sql = "SELECT %s FROM view_peers WHERE deleted IS False" % \
+        sql = "SELECT %s FROM view_peers WHERE deleted IS False" % \
               ", ".join(self.columns)
 
         if peer_filter is not None:
             if isinstance(peer_filter, (list, tuple, set)):
                 # Separate the list into integers and strings
               ", ".join(self.columns)
 
         if peer_filter is not None:
             if isinstance(peer_filter, (list, tuple, set)):
                 # Separate the list into integers and strings
-                ints = filter(lambda x: isinstance(x, (int, long)), peer_filter)
-                strs = filter(lambda x: isinstance(x, StringTypes), peer_filter)
+                ints = [x for x in peer_filter if isinstance(x, int)]
+                strs = [x for x in peer_filter if isinstance(x, str)]
                 peer_filter = Filter(Peer.fields, {'peer_id': ints, 'peername': strs})
                 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)
             elif isinstance(peer_filter, dict):
                 peer_filter = Filter(Peer.fields, peer_filter)
-                sql += " AND (%s)" % peer_filter.sql(api, "AND")
-
-       self.selectall(sql)
+                sql += " AND (%s) %s" % peer_filter.sql(api, "AND")
+            elif isinstance(peer_filter, int):
+                peer_filter = Filter(Peer.fields, {'peer_id': peer_filter})
+                sql += " AND (%s) %s" % peer_filter.sql(api, "AND")
+            elif isinstance(peer_filter, str):
+                peer_filter = Filter(Peer.fields, {'peername': peer_filter})
+                sql += " AND (%s) %s" % peer_filter.sql(api, "AND")
+            else:
+                raise PLCInvalidArgument("Wrong peer filter %r"%peer_filter)
+
+        self.selectall(sql)