dummyaggregate: fix get_slivers()
[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             if 'user_ids' in slice.keys():
96                 user_ids.extend(slice['user_ids'])
97         if user_ids:
98             users = self.driver.shell.GetUsers({'user_ids': user_ids})
99
100         # construct user key info
101         users_list = []
102         for user in users:
103             name = user['email'][0:user['email'].index('@')]
104             user = {
105                 'login': slice['slice_name'],
106                 'user_urn': Xrn('%s.%s' % (self.driver.hrn, name), type='user').urn,
107                 'keys': user['keys']
108             }
109             users_list.append(user)
110
111         if node_ids:
112             node_ids = [node_id for node_id in node_ids if node_id in slice['node_ids']]
113             slice['node_ids'] = node_ids
114         nodes_dict = self.get_slice_nodes(slice, options)
115         slivers = []
116         for node in nodes_dict.values():
117             node.update(slice)
118             sliver_hrn = '%s.%s-%s' % (self.driver.hrn, slice['slice_id'], node['node_id'])
119             node['sliver_id'] = Xrn(sliver_hrn, type='sliver').urn
120             node['urn'] = node['sliver_id']
121             node['services_user'] = users
122             slivers.append(node)
123         return slivers
124
125     def node_to_rspec_node(self, node, options={}):
126         rspec_node = NodeElement()
127         site=self.driver.testbedInfo
128         rspec_node['component_id'] = hostname_to_urn(self.driver.hrn, site['name'], node['hostname'])
129         rspec_node['component_name'] = node['hostname']
130         rspec_node['component_manager_id'] = Xrn(self.driver.hrn, 'authority+cm').get_urn()
131         rspec_node['authority_id'] = hrn_to_urn(DummyXrn.site_hrn(self.driver.hrn, site['name']), 'authority+sa')
132         #distinguish between Shared and Reservable nodes
133         rspec_node['exclusive'] = 'false'
134
135         rspec_node['hardware_types'] = [HardwareType({'name': 'dummy-pc'}),
136                                         HardwareType({'name': 'pc'})]
137         if site['longitude'] and site['latitude']:
138             location = Location({'longitude': site['longitude'], 'latitude': site['latitude'], 'country': 'unknown'})
139             rspec_node['location'] = location
140         return rspec_node
141
142     def sliver_to_rspec_node(self, sliver, sliver_allocations):
143         rspec_node = self.node_to_rspec_node(sliver)
144         rspec_node['expires'] = datetime_to_string(utcparse(sliver['expires']))
145         # add sliver info
146         rspec_sliver = Sliver({'sliver_id': sliver['urn'],
147                          'name': sliver['slice_name'],
148                          'type': 'dummy-vserver',
149                          'tags': []})
150         rspec_node['sliver_id'] = rspec_sliver['sliver_id']
151         if sliver['urn'] in sliver_allocations:
152             rspec_node['client_id'] = sliver_allocations[sliver['urn']].client_id
153             if sliver_allocations[sliver['urn']].component_id:
154                 rspec_node['component_id'] = sliver_allocations[sliver['urn']].component_id
155         rspec_node['slivers'] = [rspec_sliver]
156
157         # slivers always provide the ssh service
158         login = Login({'authentication': 'ssh-keys',
159                        'hostname': sliver['hostname'],
160                        'port':'22',
161                        'username': sliver['slice_name'],
162                        'login': sliver['slice_name']
163                       })
164         return rspec_node
165
166     def get_slice_nodes(self, slice, options={}):
167         nodes_dict = {}
168         filter = {}
169         if slice and slice.get('node_ids'):
170             filter['node_ids'] = slice['node_ids']
171         else:
172             # there are no nodes to look up
173             return nodes_dict
174         nodes = self.driver.shell.GetNodes(filter)
175         for node in nodes:
176             nodes_dict[node['node_id']] = node
177         return nodes_dict
178
179     def rspec_node_to_geni_sliver(self, rspec_node, sliver_allocations = {}):
180         if rspec_node['sliver_id'] in sliver_allocations:
181             # set sliver allocation and operational status
182             sliver_allocation = sliver_allocations[rspec_node['sliver_id']]
183             if sliver_allocation:
184                 allocation_status = sliver_allocation.allocation_state
185                 if allocation_status == 'geni_allocated':
186                     op_status =  'geni_pending_allocation'
187                 elif allocation_status == 'geni_provisioned':
188                     op_status = 'geni_ready'
189                 else:
190                     op_status = 'geni_unknown'
191             else:
192                 allocation_status = 'geni_unallocated'
193         else:
194             allocation_status = 'geni_unallocated'
195             op_status = 'geni_failed'
196         # required fields
197         geni_sliver = {'geni_sliver_urn': rspec_node['sliver_id'],
198                        'geni_expires': rspec_node['expires'],
199                        'geni_allocation_status' : allocation_status,
200                        'geni_operational_status': op_status,
201                        'geni_error': '',
202                        }
203         return geni_sliver
204
205     def list_resources(self, version = None, options={}):
206
207         version_manager = VersionManager()
208         version = version_manager.get_version(version)
209         rspec_version = version_manager._get_version(version.type, version.version, 'ad')
210         rspec = RSpec(version=rspec_version, user_options=options)
211
212         # get nodes
213         nodes  = self.get_nodes(options)
214         nodes_dict = {}
215         for node in nodes:
216             nodes_dict[node['node_id']] = node
217
218         # convert nodes to rspec nodes
219         rspec_nodes = []
220         for node in nodes:
221             rspec_node = self.node_to_rspec_node(node)
222             rspec_nodes.append(rspec_node)
223         rspec.version.add_nodes(rspec_nodes)
224
225         return rspec.toxml()
226
227     def describe(self, urns, version=None, options={}):
228         version_manager = VersionManager()
229         version = version_manager.get_version(version)
230         rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
231         rspec = RSpec(version=rspec_version, user_options=options)
232
233         # get slivers
234         geni_slivers = []
235         slivers = self.get_slivers(urns, options)
236         if slivers:
237             rspec_expires = datetime_to_string(utcparse(slivers[0]['expires']))
238         else:
239             rspec_expires = datetime_to_string(utcparse(time.time()))
240         rspec.xml.set('expires',  rspec_expires)
241
242         # lookup the sliver allocations
243         geni_urn = urns[0]
244         sliver_ids = [sliver['sliver_id'] for sliver in slivers]
245         constraint = SliverAllocation.sliver_id.in_(sliver_ids)
246         sliver_allocations = self.driver.api.dbsession().query(SliverAllocation).filter(constraint)
247         sliver_allocation_dict = {}
248         for sliver_allocation in sliver_allocations:
249             geni_urn = sliver_allocation.slice_urn
250             sliver_allocation_dict[sliver_allocation.sliver_id] = sliver_allocation
251
252         # add slivers
253         nodes_dict = {}
254         for sliver in slivers:
255             nodes_dict[sliver['node_id']] = sliver
256         rspec_nodes = []
257         for sliver in slivers:
258             rspec_node = self.sliver_to_rspec_node(sliver, sliver_allocation_dict)
259             rspec_nodes.append(rspec_node)
260             geni_sliver = self.rspec_node_to_geni_sliver(rspec_node, sliver_allocation_dict)
261             geni_slivers.append(geni_sliver)
262         rspec.version.add_nodes(rspec_nodes)
263
264         return {'geni_urn': geni_urn,
265                 'geni_rspec': rspec.toxml(),
266                 'geni_slivers': geni_slivers}
267