Merge branches 'master' and 'master' of ssh://git.onelab.eu/git/sfa
[sfa.git] / sfa / plc / aggregate.py
1 #!/usr/bin/python
2 from sfa.util.xrn import hrn_to_urn, urn_to_hrn, urn_to_sliver_id
3 from sfa.util.plxrn import PlXrn, hostname_to_urn, hrn_to_pl_slicename
4
5 from sfa.rspecs.rspec import RSpec
6 from sfa.rspecs.elements.hardware_type import HardwareType
7 from sfa.rspecs.elements.node import Node
8 from sfa.rspecs.elements.link import Link
9 from sfa.rspecs.elements.sliver import Sliver
10 from sfa.rspecs.elements.login import Login
11 from sfa.rspecs.elements.location import Location
12 from sfa.rspecs.elements.interface import Interface
13 from sfa.rspecs.elements.services import Services
14 from sfa.rspecs.elements.pltag import PLTag
15 from sfa.util.topology import Topology
16 from sfa.rspecs.version_manager import VersionManager
17 from sfa.plc.vlink import get_tc_rate
18 from sfa.util.sfatime import epochparse
19
20 class Aggregate:
21
22     api = None
23     #panos new user options variable
24     user_options = {}
25
26     def __init__(self, api, user_options={}):
27         self.api = api
28         self.user_options = user_options
29
30     def get_sites(self, filter={}):
31         sites = {}
32         for site in self.api.driver.GetSites(filter):
33             sites[site['site_id']] = site
34         return sites
35
36     def get_interfaces(self, filter={}):
37         interfaces = {}
38         for interface in self.api.driver.GetInterfaces(filter):
39             iface = Interface()
40             if interface['bwlimit']:
41                 interface['bwlimit'] = str(int(interface['bwlimit'])/1000)
42             interfaces[interface['interface_id']] = interface
43         return interfaces
44
45     def get_links(self, sites, nodes, interfaces):
46         
47         topology = Topology() 
48         links = []
49         for (site_id1, site_id2) in topology:
50             site_id1 = int(site_id1)
51             site_id2 = int(site_id2)
52             link = Link()
53             if not site_id1 in sites or site_id2 not in sites:
54                 continue
55             site1 = sites[site_id1]
56             site2 = sites[site_id2]
57             # get hrns
58             site1_hrn = self.api.hrn + '.' + site1['login_base']
59             site2_hrn = self.api.hrn + '.' + site2['login_base']
60
61             for s1_node_id in site1['node_ids']:
62                 for s2_node_id in site2['node_ids']:
63                     node1 = nodes[s1_node_id]
64                     node2 = nodes[s2_node_id]
65                     # set interfaces
66                     # just get first interface of the first node
67                     if1_xrn = PlXrn(auth=self.api.hrn, interface='node%s:eth0' % (node1['node_id']))
68                     if1_ipv4 = interfaces[node1['interface_ids'][0]]['ip']
69                     if2_xrn = PlXrn(auth=self.api.hrn, interface='node%s:eth0' % (node2['node_id']))
70                     if2_ipv4 = interfaces[node2['interface_ids'][0]]['ip']
71
72                     if1 = Interface({'component_id': if1_xrn.urn, 'ipv4': if1_ipv4} )
73                     if2 = Interface({'component_id': if2_xrn.urn, 'ipv4': if2_ipv4} )
74
75                     # set link
76                     link = Link({'capacity': '1000000', 'latency': '0', 'packet_loss': '0', 'type': 'ipv4'})
77                     link['interface1'] = if1
78                     link['interface2'] = if2
79                     link['component_name'] = "%s:%s" % (site1['login_base'], site2['login_base'])
80                     link['component_id'] = PlXrn(auth=self.api.hrn, interface=link['component_name']).get_urn()
81                     link['component_manager_id'] =  hrn_to_urn(self.api.hrn, 'authority+am')
82                     links.append(link)
83
84         return links
85
86     def get_node_tags(self, filter={}):
87         node_tags = {}
88         for node_tag in self.api.driver.GetNodeTags(filter):
89             node_tags[node_tag['node_tag_id']] = node_tag
90         return node_tags
91
92     def get_pl_initscripts(self, filter={}):
93         pl_initscripts = {}
94         filter.update({'enabled': True})
95         for initscript in self.api.driver.GetInitScripts(filter):
96             pl_initscripts[initscript['initscript_id']] = initscript
97         return pl_initscripts
98
99
100     def get_slice_and_slivers(self, slice_xrn):
101         """
102         Returns a dict of slivers keyed on the sliver's node_id
103         """
104         slivers = {}
105         slice = None
106         if not slice_xrn:
107             return (slice, slivers)
108         slice_urn = hrn_to_urn(slice_xrn, 'slice')
109         slice_hrn, _ = urn_to_hrn(slice_xrn)
110         slice_name = hrn_to_pl_slicename(slice_hrn)
111         slices = self.api.driver.GetSlices(slice_name)
112         if not slices:
113             return (slice, slivers)
114         slice = slices[0]
115
116         # sort slivers by node id    
117         for node_id in slice['node_ids']:
118             sliver = Sliver({'sliver_id': urn_to_sliver_id(slice_urn, slice['slice_id'], node_id),
119                              'name': slice['name'],
120                              'type': 'plab-vserver', 
121                              'tags': []})
122             slivers[node_id]= sliver
123
124         # sort sliver attributes by node id    
125         tags = self.api.driver.GetSliceTags({'slice_tag_id': slice['slice_tag_ids']})
126         for tag in tags:
127             # most likely a default/global sliver attribute (node_id == None)
128             if tag['node_id'] not in slivers:
129                 sliver = Sliver({'sliver_id': urn_to_sliver_id(slice_urn, slice['slice_id'], ""),
130                                  'name': 'plab-vserver',
131                                  'tags': []})
132                 slivers[tag['node_id']] = sliver
133             slivers[tag['node_id']]['tags'].append(tag)
134         
135         return (slice, slivers)
136
137     def get_nodes_and_links(self, slice=None,slivers=[]):
138         filter = {}
139         tags_filter = {}
140         if slice and 'node_ids' in slice and slice['node_ids']:
141             filter['node_id'] = slice['node_ids']
142             tags_filter=filter.copy()
143         
144         filter.update({'peer_id': None})
145         nodes = self.api.driver.GetNodes(filter)
146        
147         site_ids = []
148         interface_ids = []
149         tag_ids = []
150         nodes_dict = {}
151         for node in nodes:
152             site_ids.append(node['site_id'])
153             interface_ids.extend(node['interface_ids'])
154             tag_ids.extend(node['node_tag_ids'])
155             nodes_dict[node['node_id']] = node
156  
157         # get sites
158         sites_dict  = self.get_sites({'site_id': site_ids}) 
159         # get interfaces
160         interfaces = self.get_interfaces({'interface_id':interface_ids}) 
161         # get tags
162         node_tags = self.get_node_tags(tags_filter)
163         # get initscripts
164         pl_initscripts = self.get_pl_initscripts()
165         
166         links = self.get_links(sites_dict, nodes_dict, interfaces)
167
168         rspec_nodes = []
169         for node in nodes:
170             # skip whitelisted nodes
171             if node['slice_ids_whitelist']:
172                 if not slice or slice['slice_id'] not in node['slice_ids_whitelist']:
173                     continue
174             rspec_node = Node()
175             # xxx how to retrieve site['login_base']
176             site_id=node['site_id']
177             site=sites_dict[site_id]
178             rspec_node['component_id'] = hostname_to_urn(self.api.hrn, site['login_base'], node['hostname'])
179             rspec_node['component_name'] = node['hostname']
180             rspec_node['component_manager_id'] = self.api.hrn
181             rspec_node['authority_id'] = hrn_to_urn(PlXrn.site_hrn(self.api.hrn, site['login_base']), 'authority+sa')
182             rspec_node['boot_state'] = node['boot_state']
183             rspec_node['exclusive'] = 'False'
184             rspec_node['hardware_types']= [HardwareType({'name': 'plab-pc'}),
185                                            HardwareType({'name': 'pc'})]
186             # only doing this because protogeni rspec needs
187             # to advertise available initscripts 
188             rspec_node['pl_initscripts'] = pl_initscripts.values()
189              # add site/interface info to nodes.
190             # assumes that sites, interfaces and tags have already been prepared.
191             site = sites_dict[node['site_id']]
192             if site['longitude'] and site['latitude']:  
193                 location = Location({'longitude': site['longitude'], 'latitude': site['latitude']})
194                 rspec_node['location'] = location
195             rspec_node['interfaces'] = []
196             if_count=0
197             for if_id in node['interface_ids']:
198                 interface = Interface(interfaces[if_id]) 
199                 interface['ipv4'] = interface['ip']
200                 interface['component_id'] = PlXrn(auth=self.api.hrn, interface='node%s:eth%s' % (node['node_id'], if_count)).get_urn()
201                 rspec_node['interfaces'].append(interface)
202                 if_count+=1
203
204             tags = [PLTag(node_tags[tag_id]) for tag_id in node['node_tag_ids']]
205             rspec_node['tags'] = tags
206             if node['node_id'] in slivers:
207                 # add sliver info
208                 sliver = slivers[node['node_id']]
209                 rspec_node['sliver_id'] = sliver['sliver_id']
210                 rspec_node['client_id'] = node['hostname']
211                 rspec_node['slivers'] = [sliver]
212                 
213                 # slivers always provide the ssh service
214                 login = Login({'authentication': 'ssh-keys', 'hostname': node['hostname'], 'port':'22'})
215                 service = Services({'login': login})
216                 rspec_node['services'] = [service]
217             rspec_nodes.append(rspec_node)
218         return (rspec_nodes, links)
219              
220         
221     def get_rspec(self, slice_xrn=None, version = None):
222
223         version_manager = VersionManager()
224         version = version_manager.get_version(version)
225         if not slice_xrn:
226             rspec_version = version_manager._get_version(version.type, version.version, 'ad')
227         else:
228             rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
229
230         slice, slivers = self.get_slice_and_slivers(slice_xrn)
231         rspec = RSpec(version=rspec_version, user_options=self.user_options)
232         if slice and 'expires' in slice:
233             rspec.xml.set('expires',  epochparse(slice['expires']))
234
235         nodes, links = self.get_nodes_and_links(slice, slivers)
236         rspec.version.add_nodes(nodes)
237         rspec.version.add_links(links)
238         
239         # add sliver defaults
240         default_sliver_attribs = slivers.get(None, [])
241         for sliver_attrib in default_sliver_attribs:
242             rspec.version.add_default_sliver_attribute(sliver_attrib['name'], sliver_attrib['value'])  
243         
244         return rspec.toxml()
245
246