c6381a6127f459f25dc8b7e85cfc49bad59d3b32
[sfa.git] / sfa / dummy / dummyaggregate.py
1 #!/usr/bin/python
2 from sfa.util.xrn import Xrn, hrn_to_urn, urn_to_hrn
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 NodeElement
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 ServicesElement
15 from sfa.rspecs.elements.pltag import PLTag
16 from sfa.rspecs.elements.lease import Lease
17 from sfa.rspecs.elements.granularity import Granularity
18 from sfa.rspecs.version_manager import VersionManager
19
20 from sfa.dummy.dummyxrn import DummyXrn, hostname_to_urn, hrn_to_dummy_slicename, slicename_to_hrn
21
22 from sfa.storage.model import SliverAllocation
23 import time
24
25 class DummyAggregate:
26
27     def __init__(self, driver):
28         self.driver = driver
29
30     def get_slice_and_slivers(self, slice_xrn):
31         """
32         Returns a dict of slivers keyed on the sliver's node_id
33         """
34         slivers = {}
35         slice = None
36         if not slice_xrn:
37             return (slice, slivers)
38         slice_urn = hrn_to_urn(slice_xrn, 'slice')
39         slice_hrn, _ = urn_to_hrn(slice_xrn)
40         slice_name = hrn_to_dummy_slicename(slice_hrn)
41         slices = self.driver.shell.GetSlices({'slice_name': slice_name})
42         if not slices:
43             return (slice, slivers)
44         slice = slices[0]
45         
46         # sort slivers by node id 
47         slice_nodes = []
48         if 'node_ids' in slice.keys():
49             slice_nodes = self.driver.shell.GetNodes({'node_ids': slice['node_ids']}) 
50         for node in slice_nodes:
51             slivers[node['node_id']] = node  
52
53         return (slice, slivers)
54
55     def get_nodes(self, options={}):
56         filter = {}
57         nodes = self.driver.shell.GetNodes(filter)
58         return nodes
59
60     def get_slivers(self, urns, options={}):
61         slice_names = set()
62         slice_ids = set()
63         node_ids = []
64         for urn in urns:
65             xrn = DummyXrn(xrn=urn)
66             if xrn.type == 'sliver':
67                  # id: slice_id-node_id
68                 try:
69                     sliver_id_parts = xrn.get_sliver_id_parts()
70                     slice_id = int(sliver_id_parts[0])
71                     node_id = int(sliver_id_parts[1])
72                     slice_ids.add(slice_id)
73                     node_ids.append(node_id)
74                 except ValueError:
75                     pass
76             else:
77                 slice_names.add(xrn.dummy_slicename())
78
79         filter = {}
80         if slice_names:
81             filter['slice_name'] = list(slice_names)
82         if slice_ids:
83             filter['slice_id'] = list(slice_ids)
84         # get slices
85         slices = self.driver.shell.GetSlices(filter)
86         if not slices:
87             return []
88         slice = slices[0]
89         slice['hrn'] = DummyXrn(auth=self.driver.hrn, slicename=slice['slice_name']).hrn
90
91         # get sliver users
92         users = []
93         user_ids = []
94         for slice in slices:
95             user_ids.extend(slice['user_ids'])
96         if user_ids:
97             users = self.driver.shell.GetUsers({'user_ids': user_ids})
98
99         # construct user key info
100         users_list = []
101         for user in users:
102             name = user['email'][0:user['email'].index('@')]
103             user = {
104                 'login': slice['slice_name'],
105                 'user_urn': Xrn('%s.%s' % (self.driver.hrn, name), type='user').urn,
106                 'keys': user['keys']
107             }
108             users_list.append(user)
109
110         if node_ids:
111             node_ids = [node_id for node_id in node_ids if node_id in slice['node_ids']]
112             slice['node_ids'] = node_ids
113         nodes_dict = self.get_slice_nodes(slice, options)
114         slivers = []
115         for node in nodes_dict.values():
116             node.update(slice)
117             sliver_hrn = '%s.%s-%s' % (self.driver.hrn, slice['slice_id'], node['node_id'])
118             node['sliver_id'] = Xrn(sliver_hrn, type='sliver').urn
119             node['urn'] = node['sliver_id']
120             node['services_user'] = users
121             slivers.append(node)
122         return slivers
123
124     def node_to_rspec_node(self, node, options={}):
125         rspec_node = NodeElement()
126         site=self.driver.testbedInfo
127         rspec_node['component_id'] = hostname_to_urn(self.driver.hrn, site['name'], node['hostname'])
128         rspec_node['component_name'] = node['hostname']
129         rspec_node['component_manager_id'] = Xrn(self.driver.hrn, 'authority+cm').get_urn()
130         rspec_node['authority_id'] = hrn_to_urn(DummyXrn.site_hrn(self.driver.hrn, site['name']), 'authority+sa')
131         #distinguish between Shared and Reservable nodes
132         rspec_node['exclusive'] = 'false'
133
134         rspec_node['hardware_types'] = [HardwareType({'name': 'dummy-pc'}),
135                                         HardwareType({'name': 'pc'})]
136         if site['longitude'] and site['latitude']:
137             location = Location({'longitude': site['longitude'], 'latitude': site['latitude'], 'country': 'unknown'})
138             rspec_node['location'] = location
139         return rspec_node
140
141     def sliver_to_rspec_node(self, sliver, sliver_allocations):
142         rspec_node = self.node_to_rspec_node(sliver)
143         rspec_node['expires'] = datetime_to_string(utcparse(sliver['expires']))
144         # add sliver info
145         rspec_sliver = Sliver({'sliver_id': sliver['urn'],
146                          'name': sliver['slice_name'],
147                          'type': 'dummy-vserver',
148                          'tags': []})
149         rspec_node['sliver_id'] = rspec_sliver['sliver_id']
150         if sliver['urn'] in sliver_allocations:
151             rspec_node['client_id'] = sliver_allocations[sliver['urn']].client_id
152             if sliver_allocations[sliver['urn']].component_id:
153                 rspec_node['component_id'] = sliver_allocations[sliver['urn']].component_id
154         rspec_node['slivers'] = [rspec_sliver]
155
156         # slivers always provide the ssh service
157         login = Login({'authentication': 'ssh-keys',
158                        'hostname': sliver['hostname'],
159                        'port':'22',
160                        'username': sliver['slice_name'],
161                        'login': sliver['slice_name']
162                       })
163         return rspec_node
164
165     def get_slice_nodes(self, slice, options={}):
166         nodes_dict = {}
167         filter = {}
168         if slice and slice.get('node_ids'):
169             filter['node_ids'] = slice['node_ids']
170         else:
171             # there are no nodes to look up
172             return nodes_dict
173         nodes = self.driver.shell.GetNodes(filter)
174         for node in nodes:
175             nodes_dict[node['node_id']] = node
176         return nodes_dict
177
178     def rspec_node_to_geni_sliver(self, rspec_node, sliver_allocations = {}):
179         if rspec_node['sliver_id'] in sliver_allocations:
180             # set sliver allocation and operational status
181             sliver_allocation = sliver_allocations[rspec_node['sliver_id']]
182             if sliver_allocation:
183                 allocation_status = sliver_allocation.allocation_state
184                 if allocation_status == 'geni_allocated':
185                     op_status =  'geni_pending_allocation'
186                 elif allocation_status == 'geni_provisioned':
187                     op_status = 'geni_ready'
188                 else:
189                     op_status = 'geni_unknown'
190             else:
191                 allocation_status = 'geni_unallocated'
192         else:
193             allocation_status = 'geni_unallocated'
194             op_status = 'geni_failed'
195         # required fields
196         geni_sliver = {'geni_sliver_urn': rspec_node['sliver_id'],
197                        'geni_expires': rspec_node['expires'],
198                        'geni_allocation_status' : allocation_status,
199                        'geni_operational_status': op_status,
200                        'geni_error': '',
201                        }
202         return geni_sliver
203
204     def list_resources(self, version = None, options={}):
205
206         version_manager = VersionManager()
207         version = version_manager.get_version(version)
208         rspec_version = version_manager._get_version(version.type, version.version, 'ad')
209         rspec = RSpec(version=rspec_version, user_options=options)
210
211         # get nodes
212         nodes  = self.get_nodes(options)
213         nodes_dict = {}
214         for node in nodes:
215             nodes_dict[node['node_id']] = node
216
217         # convert nodes to rspec nodes
218         rspec_nodes = []
219         for node in nodes:
220             rspec_node = self.node_to_rspec_node(node)
221             rspec_nodes.append(rspec_node)
222         rspec.version.add_nodes(rspec_nodes)
223
224         return rspec.toxml()
225
226     def describe(self, urns, version=None, options={}):
227         version_manager = VersionManager()
228         version = version_manager.get_version(version)
229         rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
230         rspec = RSpec(version=rspec_version, user_options=options)
231
232         # get slivers
233         geni_slivers = []
234         slivers = self.get_slivers(urns, options)
235         if slivers:
236             rspec_expires = datetime_to_string(utcparse(slivers[0]['expires']))
237         else:
238             rspec_expires = datetime_to_string(utcparse(time.time()))
239         rspec.xml.set('expires',  rspec_expires)
240
241         # lookup the sliver allocations
242         geni_urn = urns[0]
243         sliver_ids = [sliver['sliver_id'] for sliver in slivers]
244         constraint = SliverAllocation.sliver_id.in_(sliver_ids)
245         sliver_allocations = self.driver.api.dbsession().query(SliverAllocation).filter(constraint)
246         sliver_allocation_dict = {}
247         for sliver_allocation in sliver_allocations:
248             geni_urn = sliver_allocation.slice_urn
249             sliver_allocation_dict[sliver_allocation.sliver_id] = sliver_allocation
250
251         # add slivers
252         nodes_dict = {}
253         for sliver in slivers:
254             nodes_dict[sliver['node_id']] = sliver
255         rspec_nodes = []
256         for sliver in slivers:
257             rspec_node = self.sliver_to_rspec_node(sliver, sliver_allocation_dict)
258             rspec_nodes.append(rspec_node)
259             geni_sliver = self.rspec_node_to_geni_sliver(rspec_node, sliver_allocation_dict)
260             geni_slivers.append(geni_sliver)
261         rspec.version.add_nodes(rspec_nodes)
262
263         return {'geni_urn': geni_urn,
264                 'geni_rspec': rspec.toxml(),
265                 'geni_slivers': geni_slivers}
266