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