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