the germ for a tool that scans the federation given entry points
[sfa.git] / sfa / client / sfascan.py
1 #!/usr/bin/python
2
3 import socket
4 import re
5
6 from sfa.client.sfi import Sfi
7 from sfa.util.sfalogging import sfa_logger,sfa_logger_goes_to_console
8 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
9
10 m_url_with_proto=re.compile("\w+://(?P<hostname>[\w\-\.]+):(?P<port>[0-9]+)/.*")
11 m_url_without_proto=re.compile("(?P<hostname>[\w\-\.]+):(?P<port>[0-9]+).*")
12 def url_to_hostname_port (url):
13     print 'url',url
14     match=m_url_with_proto.match(url)
15     if match:
16         return (match.group('hostname'),match.group('port'))
17     match=m_url_without_proto.match(url)
18     if match:
19         return (match.group('hostname'),match.group('port'))
20     return ('undefined','???')
21
22 ###
23 class Interface:
24     def __init__ (self,url,name=None):
25         self.names=[]
26         self.set_name(name)
27         try:
28             (self.hostname,self.port)=url_to_hostname_port(url)
29             self.ip=socket.gethostbyname(self.hostname)
30             self.probed=False
31         except:
32             import traceback
33             traceback.print_exc()
34             self.hostname="undefined"
35             self.port="???"
36             self.probed=True
37             self._version={}
38
39     def equal (self,against):
40         return (self.ip == against.ip) and (self.port == against.port)
41
42     def set_name (self,name):
43         if name and name not in self.names: 
44             self.names.append(name)
45
46     def url(self):
47         return "http://%s:%s"%(self.hostname,self.port)
48
49     # connect to server and trigger GetVersion
50     def get_version(self):
51         if self.probed:
52             return self._version
53         # dummy to meet Sfi's expectations for its 'options' field
54         class DummyOptions:
55             pass
56         options=DummyOptions()
57         options.verbose=False
58         try:
59             client=Sfi(options)
60             client.read_config()
61             key_file = client.get_key_file()
62             cert_file = client.get_cert_file(key_file)
63             url="http://%s:%s/"%(self.hostname,self.port)
64             sfa_logger().info('issuing get version at %s'%url)
65             server=xmlrpcprotocol.get_server(url, key_file, cert_file, options)
66             self._version=server.GetVersion()
67 #            pdb.set_trace()
68         except:
69             self._version={}
70         self.probed=True
71         return self._version
72
73 class SfaScan:
74
75     # provide the entry points (a list of interfaces)
76     def __init__ (self):
77         pass
78
79     # scan from the given interfaces as entry points
80     def scan(self,interfaces):
81         import pdb
82 #        pdb.set_trace()
83         if not isinstance(interfaces,list):
84             interfaces=[interfaces]
85         # should add nodes, but with what name ?
86         to_scan=interfaces
87         scanned=[]
88         def was_scanned (interface):
89             for i in scanned:
90                 if interface.equal(i): return i
91             return False
92         # keep on looping until we reach a fixed point
93         while to_scan:
94             for interface in to_scan:
95                 version=interface.get_version()
96                 if 'peers' in version: 
97                     for (next_name,next_url) in version['peers'].items():
98                         # should add edge
99                         next_interface=Interface(next_url)
100                         seen_interface=was_scanned(next_interface)
101                         if seen_interface:
102                             # record name
103                             seen_interface.set_name(next_name)
104                         else:
105                             sfa_logger().info('adding %s'%next_interface.url())
106                             to_scan.append(next_interface)
107                             
108                 scanned.append(interface)
109                 to_scan.remove(interface)
110     
111
112 def main():
113     sfa_logger_goes_to_console()
114     scanner=SfaScan()
115     entry=Interface("http://www.planet-lab.eu:12345/")
116     scanner.scan(entry)
117
118 if __name__ == '__main__':
119     main()