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