Removed hard coded login in GET requests (OARrestapi).
[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 utcparse, datetime_to_string
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  
28     def get_sites(self, filter={}):
29         sites = {}
30         for site in self.driver.shell.GetSites(filter):
31             sites[site['site_id']] = site
32         return sites
33
34     def get_interfaces(self, filter={}):
35         interfaces = {}
36         for interface in self.driver.shell.GetInterfaces(filter):
37             iface = Interface()
38             if interface['bwlimit']:
39                 interface['bwlimit'] = str(int(interface['bwlimit'])/1000)
40             interfaces[interface['interface_id']] = interface
41         return interfaces
42
43     def get_links(self, sites, nodes, interfaces):
44         
45         topology = Topology() 
46         links = []
47         for (site_id1, site_id2) in topology:
48             site_id1 = int(site_id1)
49             site_id2 = int(site_id2)
50             link = Link()
51             if not site_id1 in sites or site_id2 not in sites:
52                 continue
53             site1 = sites[site_id1]
54             site2 = sites[site_id2]
55             # get hrns
56             site1_hrn = self.driver.hrn + '.' + site1['login_base']
57             site2_hrn = self.driver.hrn + '.' + site2['login_base']
58
59             for s1_node_id in site1['node_ids']:
60                 for s2_node_id in site2['node_ids']:
61                     if s1_node_id not in nodes or s2_node_id not in nodes:
62                         continue
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.driver.hrn, interface='node%s:eth0' % (node1['node_id']))
68                     if1_ipv4 = interfaces[node1['interface_ids'][0]]['ip']
69                     if2_xrn = PlXrn(auth=self.driver.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.driver.hrn, interface=link['component_name']).get_urn()
81                     link['component_manager_id'] =  hrn_to_urn(self.driver.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.driver.shell.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.driver.shell.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.driver.shell.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.driver.shell.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': slice['name'],
131                                  'type': '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.shell.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             # do not include boot state (<available> element) in the manifest rspec
188             if not slice:     
189                 rspec_node['boot_state'] = node['boot_state']
190             rspec_node['exclusive'] = 'false'
191             rspec_node['hardware_types'] = [HardwareType({'name': 'plab-pc'}),
192                                             HardwareType({'name': 'pc'})]
193             # only doing this because protogeni rspec needs
194             # to advertise available initscripts 
195             rspec_node['pl_initscripts'] = pl_initscripts.values()
196              # add site/interface info to nodes.
197             # assumes that sites, interfaces and tags have already been prepared.
198             site = sites_dict[node['site_id']]
199             if site['longitude'] and site['latitude']:  
200                 location = Location({'longitude': site['longitude'], 'latitude': site['latitude'], 'country': 'unknown'})
201                 rspec_node['location'] = location
202             rspec_node['interfaces'] = []
203             if_count=0
204             for if_id in node['interface_ids']:
205                 interface = Interface(interfaces[if_id]) 
206                 interface['ipv4'] = interface['ip']
207                 interface['component_id'] = PlXrn(auth=self.driver.hrn, 
208                                                   interface='node%s:eth%s' % (node['node_id'], if_count)).get_urn()
209                 # interfaces in the manifest need a client id
210                 if slice:
211                     interface['client_id'] = "%s:%s" % (node['node_id'], if_id)            
212                 rspec_node['interfaces'].append(interface)
213                 if_count+=1
214
215             tags = [PLTag(node_tags[tag_id]) for tag_id in node['node_tag_ids']]
216             rspec_node['tags'] = tags
217             if node['node_id'] in slivers:
218                 # add sliver info
219                 sliver = slivers[node['node_id']]
220                 rspec_node['sliver_id'] = sliver['sliver_id']
221                 rspec_node['client_id'] = node['hostname']
222                 rspec_node['slivers'] = [sliver]
223                 
224                 # slivers always provide the ssh service
225                 login = Login({'authentication': 'ssh-keys', 'hostname': node['hostname'], 'port':'22', 'username': sliver['name']})
226                 service = Services({'login': login})
227                 rspec_node['services'] = [service]
228             rspec_nodes.append(rspec_node)
229         return (rspec_nodes, links)
230              
231         
232     def get_rspec(self, slice_xrn=None, version = None, options={}):
233
234         version_manager = VersionManager()
235         version = version_manager.get_version(version)
236         if not slice_xrn:
237             rspec_version = version_manager._get_version(version.type, version.version, 'ad')
238         else:
239             rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
240
241         slice, slivers = self.get_slice_and_slivers(slice_xrn)
242         rspec = RSpec(version=rspec_version, user_options=options)
243         if slice and 'expires' in slice:
244             rspec.xml.set('expires',  datetime_to_string(utcparse(slice['expires'])))
245
246         nodes, links = self.get_nodes_and_links(slice, slivers)
247         rspec.version.add_nodes(nodes)
248         rspec.version.add_links(links)
249         
250         # add sliver defaults
251         default_sliver = slivers.get(None, [])
252         if default_sliver:
253             default_sliver_attribs = default_sliver.get('tags', [])
254             for attrib in default_sliver_attribs:
255                 logger.info(attrib)
256                 rspec.version.add_default_sliver_attribute(attrib['tagname'], attrib['value'])
257         return rspec.toxml()
258
259