afd72352bf657941ace0ad8f82297bd498e90ef9
[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                     if s1_node_id not in nodes or s2_node_id not in nodes:
64                         continue
65                     node1 = nodes[s1_node_id]
66                     node2 = nodes[s2_node_id]
67                     # set interfaces
68                     # just get first interface of the first node
69                     if1_xrn = PlXrn(auth=self.api.hrn, interface='node%s:eth0' % (node1['node_id']))
70                     if1_ipv4 = interfaces[node1['interface_ids'][0]]['ip']
71                     if2_xrn = PlXrn(auth=self.api.hrn, interface='node%s:eth0' % (node2['node_id']))
72                     if2_ipv4 = interfaces[node2['interface_ids'][0]]['ip']
73
74                     if1 = Interface({'component_id': if1_xrn.urn, 'ipv4': if1_ipv4} )
75                     if2 = Interface({'component_id': if2_xrn.urn, 'ipv4': if2_ipv4} )
76
77                     # set link
78                     link = Link({'capacity': '1000000', 'latency': '0', 'packet_loss': '0', 'type': 'ipv4'})
79                     link['interface1'] = if1
80                     link['interface2'] = if2
81                     link['component_name'] = "%s:%s" % (site1['login_base'], site2['login_base'])
82                     link['component_id'] = PlXrn(auth=self.api.hrn, interface=link['component_name']).get_urn()
83                     link['component_manager_id'] =  hrn_to_urn(self.api.hrn, 'authority+am')
84                     links.append(link)
85
86         return links
87
88     def get_node_tags(self, filter={}):
89         node_tags = {}
90         for node_tag in self.api.driver.GetNodeTags(filter):
91             node_tags[node_tag['node_tag_id']] = node_tag
92         return node_tags
93
94     def get_pl_initscripts(self, filter={}):
95         pl_initscripts = {}
96         filter.update({'enabled': True})
97         for initscript in self.api.driver.GetInitScripts(filter):
98             pl_initscripts[initscript['initscript_id']] = initscript
99         return pl_initscripts
100
101
102     def get_slice_and_slivers(self, slice_xrn):
103         """
104         Returns a dict of slivers keyed on the sliver's node_id
105         """
106         slivers = {}
107         slice = None
108         if not slice_xrn:
109             return (slice, slivers)
110         slice_urn = hrn_to_urn(slice_xrn, 'slice')
111         slice_hrn, _ = urn_to_hrn(slice_xrn)
112         slice_name = hrn_to_pl_slicename(slice_hrn)
113         slices = self.api.driver.GetSlices(slice_name)
114         if not slices:
115             return (slice, slivers)
116         slice = slices[0]
117
118         # sort slivers by node id    
119         for node_id in slice['node_ids']:
120             sliver = Sliver({'sliver_id': urn_to_sliver_id(slice_urn, slice['slice_id'], node_id),
121                              'name': slice['name'],
122                              'type': 'plab-vserver', 
123                              'tags': []})
124             slivers[node_id]= sliver
125
126         # sort sliver attributes by node id    
127         tags = self.api.driver.GetSliceTags({'slice_tag_id': slice['slice_tag_ids']})
128         for tag in tags:
129             # most likely a default/global sliver attribute (node_id == None)
130             if tag['node_id'] not in slivers:
131                 sliver = Sliver({'sliver_id': urn_to_sliver_id(slice_urn, slice['slice_id'], ""),
132                                  'name': 'plab-vserver',
133                                  'tags': []})
134                 slivers[tag['node_id']] = sliver
135             slivers[tag['node_id']]['tags'].append(tag)
136         
137         return (slice, slivers)
138
139     def get_nodes_and_links(self, slice=None,slivers=[]):
140         filter = {}
141         tags_filter = {}
142         if slice and 'node_ids' in slice and slice['node_ids']:
143             filter['node_id'] = slice['node_ids']
144             tags_filter=filter.copy()
145         
146         filter.update({'peer_id': None})
147         nodes = self.api.driver.GetNodes(filter)
148        
149         site_ids = []
150         interface_ids = []
151         tag_ids = []
152         nodes_dict = {}
153         for node in nodes:
154             site_ids.append(node['site_id'])
155             interface_ids.extend(node['interface_ids'])
156             tag_ids.extend(node['node_tag_ids'])
157             nodes_dict[node['node_id']] = node
158  
159         # get sites
160         sites_dict  = self.get_sites({'site_id': site_ids}) 
161         # get interfaces
162         interfaces = self.get_interfaces({'interface_id':interface_ids}) 
163         # get tags
164         node_tags = self.get_node_tags(tags_filter)
165         # get initscripts
166         pl_initscripts = self.get_pl_initscripts()
167         
168         links = self.get_links(sites_dict, nodes_dict, interfaces)
169
170         rspec_nodes = []
171         for node in nodes:
172             # skip whitelisted nodes
173             if node['slice_ids_whitelist']:
174                 if not slice or slice['slice_id'] not in node['slice_ids_whitelist']:
175                     continue
176             rspec_node = Node()
177             # xxx how to retrieve site['login_base']
178             site_id=node['site_id']
179             site=sites_dict[site_id]
180             rspec_node['component_id'] = hostname_to_urn(self.api.hrn, site['login_base'], node['hostname'])
181             rspec_node['component_name'] = node['hostname']
182             rspec_node['component_manager_id'] = self.api.hrn
183             rspec_node['authority_id'] = hrn_to_urn(PlXrn.site_hrn(self.api.hrn, site['login_base']), 'authority+sa')
184             rspec_node['boot_state'] = node['boot_state']
185             rspec_node['exclusive'] = 'False'
186             rspec_node['hardware_types']= [HardwareType({'name': 'plab-pc'}),
187                                            HardwareType({'name': 'pc'})]
188             # only doing this because protogeni rspec needs
189             # to advertise available initscripts 
190             rspec_node['pl_initscripts'] = pl_initscripts.values()
191              # add site/interface info to nodes.
192             # assumes that sites, interfaces and tags have already been prepared.
193             site = sites_dict[node['site_id']]
194             if site['longitude'] and site['latitude']:  
195                 location = Location({'longitude': site['longitude'], 'latitude': site['latitude']})
196                 rspec_node['location'] = location
197             rspec_node['interfaces'] = []
198             if_count=0
199             for if_id in node['interface_ids']:
200                 interface = Interface(interfaces[if_id]) 
201                 interface['ipv4'] = interface['ip']
202                 interface['component_id'] = PlXrn(auth=self.api.hrn, interface='node%s:eth%s' % (node['node_id'], if_count)).get_urn()
203                 rspec_node['interfaces'].append(interface)
204                 if_count+=1
205
206             tags = [PLTag(node_tags[tag_id]) for tag_id in node['node_tag_ids']]
207             rspec_node['tags'] = tags
208             if node['node_id'] in slivers:
209                 # add sliver info
210                 sliver = slivers[node['node_id']]
211                 rspec_node['sliver_id'] = sliver['sliver_id']
212                 rspec_node['client_id'] = node['hostname']
213                 rspec_node['slivers'] = [sliver]
214                 
215                 # slivers always provide the ssh service
216                 login = Login({'authentication': 'ssh-keys', 'hostname': node['hostname'], 'port':'22'})
217                 service = Services({'login': login})
218                 rspec_node['services'] = [service]
219             rspec_nodes.append(rspec_node)
220         return (rspec_nodes, links)
221              
222         
223     def get_rspec(self, slice_xrn=None, version = None):
224
225         version_manager = VersionManager()
226         version = version_manager.get_version(version)
227         if not slice_xrn:
228             rspec_version = version_manager._get_version(version.type, version.version, 'ad')
229         else:
230             rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
231
232         slice, slivers = self.get_slice_and_slivers(slice_xrn)
233         rspec = RSpec(version=rspec_version, user_options=self.user_options)
234         if slice and 'expires' in slice:
235             rspec.xml.set('expires',  epochparse(slice['expires']))
236
237         nodes, links = self.get_nodes_and_links(slice, slivers)
238         rspec.version.add_nodes(nodes)
239         rspec.version.add_links(links)
240         
241         # add sliver defaults
242         default_sliver_attribs = slivers.get(None, [])
243         for sliver_attrib in default_sliver_attribs:
244             rspec.version.add_default_sliver_attribute(sliver_attrib['name'], sliver_attrib['value'])  
245         
246         return rspec.toxml()
247
248