Merge branch 'upstreammaster'
[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.login import Login
10 from sfa.rspecs.elements.location import Location
11 from sfa.rspecs.elements.interface import Interface
12 from sfa.rspecs.elements.services import Services
13 from sfa.rspecs.elements.pltag import PLTag
14 from sfa.util.topology import Topology
15 from sfa.rspecs.version_manager import VersionManager
16 from sfa.plc.vlink import get_tc_rate
17
18 class Aggregate:
19
20     api = None
21     #panos new user options variable
22     user_options = {}
23
24     def __init__(self, api, user_options={}):
25         self.api = api
26         self.user_options = user_options
27
28     def get_sites(self, filter={}):
29         sites = {}
30         for site in self.api.driver.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.api.driver.GetInterfaces(filter):
37             iface = Interface()
38             iface['interface_id'] = interface['interface_id']
39             iface['node_id'] = interface['node_id']
40             iface['ipv4'] = interface['ip']
41             iface['bwlimit'] = interface['bwlimit']
42             interfaces[iface['interface_id']] = iface
43         return interfaces
44
45     def get_links(self, filter={}):
46         
47         if not self.api.config.SFA_AGGREGATE_TYPE.lower() == 'vini':
48             return []
49
50         topology = Topology() 
51         links = {}
52         for (site_id1, site_id2) in topology:
53             link = Link()
54             if not site_id1 in self.sites or site_id2 not in self.sites:
55                 continue
56             site1 = self.sites[site_id1]
57             site2 = self.sites[site_id2]
58             # get hrns
59             site1_hrn = self.api.hrn + '.' + site1['login_base']
60             site2_hrn = self.api.hrn + '.' + site2['login_base']
61             # get the first node
62             node1 = self.nodes[site1['node_ids'][0]]
63             node2 = self.nodes[site2['node_ids'][0]]
64
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 = self.interfaces[node1['interface_ids'][0]]['ip']
69             if2_xrn = PlXrn(auth=self.api.hrn, interface='node%s:eth0' % (node2['node_id']))
70             if2_ipv4 = self.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[link['component_name']] = 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)
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': 'plab-vserver', 
120                              'tags': []})
121             slivers[node_id]= sliver
122
123         # sort sliver attributes by node id    
124         tags = self.api.driver.GetSliceTags({'slice_tag_id': slice['slice_tag_ids']})
125         for tag in tags:
126             # most likely a default/global sliver attribute (node_id == None)
127             if tag['node_id'] not in slivers:
128                 sliver = Sliver({'sliver_id': urn_to_sliver_id(slice_urn, slice['slice_id'], ""),
129                                  'name': 'plab-vserver',
130                                  'tags': []})
131                 slivers[tag['node_id']] = sliver
132             slivers[tag['node_id']]['tags'].append(tag)
133         
134         return (slice, slivers)
135
136     def get_nodes (self, slice=None,slivers=[]):
137         filter = {}
138         tags_filter = {}
139         if slice and 'node_ids' in slice and slice['node_ids']:
140             filter['node_id'] = slice['node_ids']
141             tags_filter=filter.copy()
142         
143         filter.update({'peer_id': None})
144         nodes = self.api.driver.GetNodes(filter)
145        
146         site_ids = []
147         interface_ids = []
148         tag_ids = []
149         for node in nodes:
150             site_ids.append(node['site_id'])
151             interface_ids.extend(node['interface_ids'])
152             tag_ids.extend(node['node_tag_ids'])
153  
154         # get sites
155         sites_dict  = self.get_sites({'site_id': site_ids}) 
156         # get interfaces
157         interfaces = self.get_interfaces({'interface_id':interface_ids}) 
158         # get slivers
159         # 
160         # thierry: no get_slivers, we have slivers as a result of
161         # get_slice_and_slivers passed as an argument
162         # 
163 #        slivers = self.get_slivers(slice)
164
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'].append(HardwareType({'name': 'plab-vserver'}))
187             # only doing this because protogeni rspec needs
188             # to advertise available initscripts 
189             rspec_node['pl_initscripts'] = pl_initscripts
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             location = Location({'longitude': site['longitude'], 'latitude': site['latitude']})
194             rspec_node['location'] = location
195             rspec_node['interfaces'] = []
196             for if_id in node['interface_ids']:
197                 interface = Interface(interfaces[if_id]) 
198                 interface['ipv4'] = interface['ipv4']
199                 rspec_node['interfaces'].append(interface)
200             tags = [PLTag(node_tags[tag_id]) for tag_id in node['node_tag_ids']]
201             rspec_node['tags'] = tags
202             if node['node_id'] in slivers:
203                 # add sliver info
204                 sliver = slivers[node['node_id']]
205                 rspec_node['sliver_id'] = sliver['sliver_id']
206                 rspec_node['client_id'] = node['hostname']
207                 rspec_node['slivers'] = [slivers[node['node_id']]]
208                 
209                 # slivers always provide the ssh service
210                 login = Login({'authentication': 'ssh-keys', 'hostname': node['hostname'], port:'22'})
211                 service = Services({'login': login})
212                 rspec_node['services'].append(service)
213             rspec_nodes.append(rspec_node)
214         return rspec_nodes
215              
216         
217     def get_rspec(self, slice_xrn=None, version = None):
218
219         version_manager = VersionManager()
220         version = version_manager.get_version(version)
221         if not slice_xrn:
222             rspec_version = version_manager._get_version(version.type, version.version, 'ad')
223         else:
224             rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
225
226         slice, slivers = self.get_slice_and_slivers(slice_xrn)
227         rspec = RSpec(version=rspec_version, user_options=self.user_options)
228         rspec.version.add_nodes(self.get_nodes(slice), slivers)
229         rspec.version.add_links(self.get_links(slice))
230         
231         # add sliver defaults
232         default_sliver_attribs = slivers.get(None, [])
233         for sliver_attrib in default_sliver_attribs:
234             rspec.version.add_default_sliver_attribute(sliver_attrib['name'], sliver_attrib['value'])  
235         
236         return rspec.toxml()
237
238