6 from geni.util.geniserver import *
7 from geni.util.geniclient import *
8 from geni.util.cert import *
9 from geni.util.trustedroot import *
10 from geni.util.excep import *
11 from geni.util.misc import *
12 from geni.util.config import Config
13 from geni.util.rspec import Rspec
14 from geni.util.specdict import *
15 from geni.util.storage import SimpleStorage
17 class SliceMgr(GeniServer):
33 # Create a new slice manager object.
35 # @param ip the ip address to listen on
36 # @param port the port to listen on
37 # @param key_file private key filename of registry
38 # @param cert_file certificate filename containing public key (could be a GID file)
40 def __init__(self, ip, port, key_file, cert_file, config = "/usr/share/geniwrapper/util/geni_config"):
41 GeniServer.__init__(ip, port, key_file, cert_file)
42 self.key_file = key_file
43 self.cert_file = cert_file
44 self.conf = Config(config)
45 basedir = self.conf.GENI_BASE_DIR + os.sep
46 server_basedir = basedir + os.sep + "geni" + os.sep
47 self.hrn = conf.GENI_INTERFACE_HRN
49 # Get list of aggregates this sm talks to
50 aggregates_file = server_basedir + os.sep + 'aggregates'
51 self.aggregates = SimpleStorage(aggregates_file)
52 self.load_aggregates(aggregates_file)
54 components_file = os.sep.join([server_basedir, 'components', 'slicemgr.' + hrn + '.comp'])
56 self.slices_file = os.sep.join([server_basedir, 'components', 'slicemgr' + hrn + '.slices'])
57 self.timestamp_file = os.sep.join([server_basedir, 'components', 'slicemgr' + hrn + '.timestamp'])
58 self.components_ttl = components_ttl
59 self.policy['whitelist'] = []
60 self.policy['blacklist'] = []
63 def load_aggregates(self, aggregates_file):
65 Get info about the aggregates available to us from file and create
66 an xmlrpc connection to each. If any info is invalid, skip it.
70 f = open(aggregates_file, 'r')
77 if line.strip.startswith("#"):
79 agg_info = line.split("\t").split(" ")
82 if len(agg_info) != 3:
85 # create xmlrpc connection using GeniClient
86 hrn, address, port = agg_info[0], agg_info[1], agg_info[2]
87 url = 'https://%(address)s:%(port)s' % locals()
88 self.aggregates[hrn] = GeniClient(url, self.key_file, self.cert_file)
91 def item_hrns(self, items):
93 Take a list of items (components or slices) and return a dictionary where
94 the key is the authoritative hrn and the value is a list of items at that
98 agg_hrns = self.aggregates.keys()
99 for agg_hrn in agg_hrns:
100 item_hrns[agg_hrn] = []
102 for agg_hrn in agg_hrns:
103 if item.startswith(agg_hrn):
104 item_hrns[agg_hrn] = item
109 def hostname_to_hrn(self, login_base, hostname):
111 Convert hrn to plantelab name.
113 genihostname = "_".join(hostname.split("."))
114 return ".".join([self.hrn, login_base, genihostname])
116 def slicename_to_hrn(self, slicename):
118 Convert hrn to planetlab name.
120 slicename = slicename.replace("_", ".")
121 return ".".join([self.hrn, slicename])
123 def refresh_components(self):
125 Update the cached list of nodes.
129 aggregates = self.aggregates.keys()
132 for aggregate in aggregates:
134 # resolve components hostnames
135 nodes = self.aggregates[aggregate].get_components()
136 all_nodes.extend(nodes)
137 # update timestamp and threshold
138 self.timestamp = datetime.datetime.now()
139 delta = datetime.timedelta(hours=self.components_ttl)
140 self.threshold = self.timestamp + delta
142 # XX print out to some error log
145 self.components = all_nodes
146 f = open(self.components_file, 'w')
147 f.write(str(self.components))
149 f = open(self.timestamp_file, 'w')
150 f.write(str(self.threshold))
153 def load_components(self):
155 Read cached list of nodes and slices.
157 print "loading nodes"
158 # Read component list from cached file
159 if os.path.exists(self.components_file):
160 f = open(self.components_file, 'r')
161 self.components = eval(f.read())
164 time_format = "%Y-%m-%d %H:%M:%S"
165 if os.path.exists(self.timestamp_file):
166 f = open(self.timestamp_file, 'r')
167 timestamp = str(f.read()).split(".")[0]
168 self.timestamp = datetime.datetime.fromtimestamp(time.mktime(time.strptime(timestamp, time_format)))
169 delta = datetime.timedelta(hours=self.components_ttl)
170 self.threshold = self.timestamp + delta
173 def load_policy(self):
175 Read the list of blacklisted and whitelisted nodes.
179 if os.path.exists(self.whitelist_file):
180 f = open(self.whitelist_file, 'r')
181 lines = f.readlines()
184 line = line.strip().replace(" ", "").replace("\n", "")
185 whitelist.extend(line.split(","))
188 if os.path.exists(self.blacklist_file):
189 f = open(self.blacklist_file, 'r')
190 lines = f.readlines()
193 line = line.strip().replace(" ", "").replace("\n", "")
194 blacklist.extend(line.split(","))
196 self.policy['whitelist'] = whitelist
197 self.policy['blacklist'] = blacklist
199 def load_slices(self):
201 Read current slice instantiation states.
203 print "loading slices"
204 if os.path.exists(self.slices_file):
205 f = open(self.components_file, 'r')
206 self.slices = eval(f.read())
209 def write_slices(self):
211 Write current slice instantiations to file.
213 print "writing slices"
214 f = open(self.slices_file, 'w')
215 f.write(str(self.slices))
219 def get_components(self):
221 Return a list of components managed by this slice manager.
223 # Reload components list
224 now = datetime.datetime.now()
225 #self.load_components()
226 if not self.threshold or not self.timestamp or now > self.threshold:
227 self.refresh_components()
228 elif now < self.threshold and not self.components:
229 self.load_components()
230 return self.components
233 def get_slices(self):
235 Return a list of instnatiated managed by this slice manager.
237 now = datetime.datetime.now()
238 #self.load_components()
239 if not self.threshold or not self.timestamp or now > self.threshold:
240 self.refresh_components()
241 elif now < self.threshold and not self.slices:
242 self.load_components()
245 def get_slivers(self, hrn):
247 Return the list of slices instantiated at the specified component.
250 # hrn is assumed to be a component hrn
251 if hrn not in self.slices:
252 raise RecordNotFound(hrn)
254 return self.slices[hrn]
256 def get_rspec(self, hrn, type):
259 nodes = self.shell.GetNodes(self.auth)
260 elif type in ['slice']:
261 slices = self.shell.GetSlices(self.auth)
262 elif type in ['aggregate']:
265 def get_resources(self, slice_hrn):
267 Return the current rspec for the specified slice.
269 slicename = hrn_to_plcslicename(slice_hrn)
270 rspec = self.get_rspec(slicenamem, 'slice' )
274 def create_slice(self, slice_hrn, rspec, attributes):
276 Instantiate the specified slice according to whats defined in the rspec.
278 slicename = self.hrn_to_plcslicename(slice_hrn)
281 #for netspec in spec['networks]:
282 # networkname = netspec['name']
283 # nodespec = spec['networks']['nodes']
284 # nodes = [nspec['name'] for nspec in nodespec]
285 # node_hrns = [networkname + node for node in nodes]
287 self.db.AddSliceToNodes(slice_hrn, node_hrns)
290 def delete_slice_(self, slice_hrn):
292 Remove this slice from all components it was previouly associated with and
293 free up the resources it was using.
295 self.db.DeleteSliceFromNodes(self.auth, slicename, self.components)
298 def start_slice(self, slice_hrn):
300 Stop the slice at plc.
302 slicename = hrn_to_plcslicename(slice_hrn)
303 slices = self.shell.GetSlices(self.auth, {'name': slicename}, ['slice_id'])
305 raise RecordNotFound(slice_hrn)
307 atrribtes = self.shell.GetSliceAttributes({'slice_id': slice_id, 'name': 'enabled'}, ['slice_attribute_id'])
308 attribute_id = attreibutes[0]
309 self.shell.UpdateSliceAttribute(self.auth, attribute_id, "1" )
312 def stop_slice(self, slice_hrn):
314 Stop the slice at plc
316 slicename = hrn_to_plcslicename(slice_hrn)
317 slices = self.shell.GetSlices(self.auth, {'name': slicename}, ['slice_id'])
319 raise RecordNotFound(slice_hrn)
321 atrribtes = self.shell.GetSliceAttributes({'slice_id': slice_id, 'name': 'enabled'}, ['slice_attribute_id'])
322 attribute_id = attreibutes[0]
323 self.shell.UpdateSliceAttribute(self.auth, attribute_id, "0")
326 def reset_slice(self, slice_hrn):
330 slicename = self.hrn_to_plcslicename(slice_hrn)
333 def get_policy(self):
335 Return the policy of this slice manager.
342 ##############################
343 ## Server methods here for now
344 ##############################
347 return self.get_components()
350 return self.get_slices()
352 def resources(self, cred, hrn):
353 self.decode_authentication(cred, 'info')
354 self.verify_object_belongs_to_me(hrn)
356 return self.get_resources(hrn)
358 def create(self, cred, hrn, rspec):
359 self.decode_authentication(cred, 'embed')
360 self.verify_object_belongs_to_me(hrn, rspec)
361 return self.create(hrn)
363 def delete(self, cred, hrn):
364 self.decode_authentication(cred, 'embed')
365 self.verify_object_belongs_to_me(hrn)
366 return self.delete_slice(hrn)
368 def start(self, cred, hrn):
369 self.decode_authentication(cred, 'control')
370 return self.start(hrn)
372 def stop(self, cred, hrn):
373 self.decode_authentication(cred, 'control')
374 return self.stop(hrn)
376 def reset(self, cred, hrn):
377 self.decode_authentication(cred, 'control')
378 return self.reset(hrn)
380 def policy(self, cred):
381 self.decode_authentication(cred, 'info')
382 return self.get_policy()
384 def register_functions(self):
385 GeniServer.register_functions(self)
387 # Aggregate interface methods
388 self.server.register_function(self.components)
389 self.server.register_function(self.slices)
390 self.server.register_function(self.resources)
391 self.server.register_function(self.create)
392 self.server.register_function(self.delete)
393 self.server.register_function(self.start)
394 self.server.register_function(self.stop)
395 self.server.register_function(self.reset)
396 self.server.register_function(self.policy)