4 # NodeManager plugin - first step of handling reservable nodes
7 Manages running slices when reservation_policy is 'lease_or_idle' or 'lease_or_shared'
17 # this instructs nodemanager that we want to use the latest known data in case the plc link is down
18 persistent_data = True
20 # of course things would be simpler if node manager was to create one instance of the plugins
21 # instead of blindly caling functions in the module...
23 ##############################
24 # rough implementation for a singleton class
25 def Singleton (klass,*args,**kwds):
26 if not hasattr(klass,'_instance'):
27 klass._instance=klass(*args,**kwds)
28 return klass._instance
30 def start(options, conf):
31 return Singleton(reservation).start(options,conf)
33 def GetSlivers(data, conf = None, plc = None):
34 return Singleton(reservation).GetSlivers(data, conf, plc)
36 ##############################
40 # the last snapshot of data exposed by GetSlivers
42 # this is a dict mapping a raounded timestamp to the corr. Timer object
45 # the granularity is set in the API (initial value is 15 minutes)
46 # and it used to round all leases start/until times
47 # changing this dynamically can have some weird effects of course..
48 def granularity (self):
50 return self.data['lease_granularity']
51 # in case we'd try to access this before it's populated..
55 # round to granularity
56 def round_time (self, time):
57 granularity=self.granularity()
58 return ((int(time)+granularity/2)/granularity)*granularity
60 def clear_timers (self):
61 for timer in self.timers.values():
65 def clear_timer (self,timestamp):
66 round=self.round_time(timestamp)
67 if round in self.timers:
68 timer=self.timers[round]
70 del self.timers[round]
72 def sync_timers_from_leases (self):
74 for lease in self.data['leases']:
75 self.ensure_timer(lease['t_from'])
76 self.ensure_timer(lease['t_until'])
78 def ensure_timer(self, timestamp):
80 # forget about past events
81 if timestamp < now: return
82 round=self.round_time(timestamp)
83 if round in self.timers: return
85 self.round_time_callback (round)
86 timer=threading.Timer(timestamp-now,this_closure)
87 self.timers[round]=timer
90 def round_time_callback (self, time_arg):
92 round_now=self.round_time(now)
93 logger.log('reservation.round_time_callback now=%f round_now=%d arg=%d...'%(now,round_now,time_arg))
94 leases=self.data.leases
96 logger.verbose('Listing leases beg')
98 logger.verbose("lease=%r"%lease)
99 logger.verbose('Listing leases end')
101 if lease['t_until']==round_now:
102 logger.log('Suspending slice %s - ending lease %d'%(lease['name'],lease['lease_id']))
103 self.suspend_slice (lease['name'])
105 if lease['t_from']==round_now:
106 logger.log('Starting slice %s - starting lease %d'%(lease['name'],lease['lease_id']))
107 self.restart_slice (lease['name'])
110 def suspend_slice(self, slicename):
111 logger.log('reservation.suspend_slice, slice %s, to be written'%slicename)
113 def restart_slice(self, slicename):
114 logger.log('reservation.restart_slice, slice %s, to be written'%slicename)
116 def show_time (self, timestamp):
117 return time.strftime ("%Y-%m-%d %H:%M %Z",time.gmtime(timestamp))
120 def start(self,options,conf):
121 logger.log("reservation: plugin performing dummy start...")
123 # this method is entirely about making sure that we have events scheduled
124 # at the <granularity> intervals where there is a lease that starts or ends
125 def GetSlivers (self, data, conf=None, plc=None):
127 # check we're using a compliant GetSlivers
128 if 'reservation_policy' not in data:
129 logger.log_missing_data("reservation.GetSlivers",'reservation_policy')
131 reservation_policy=data['reservation_policy']
132 if 'leases' not in data:
133 logger.log_missing_data("reservation.GetSlivers",'leases')
138 # since we've asked for persistent_data, we should not get an empty data here
139 if data: self.data = data
141 # regular nodes are not affected
142 if reservation_policy == 'none':
144 elif reservation_policy not in ['lease_or_idle','lease_or_shared']:
145 logger.log("reservation: ignoring -- unexpected value for reservation_policy %r"%reservation_policy)
147 # at this point we have reservation_policy in ['lease_or_idle','lease_or_shared']
148 # we make no difference for now
149 logger.verbose('reservation.GetSlivers : reservable node -- listing timers ')
151 self.sync_timers_from_leases()
152 for timestamp in self.timers.keys():
153 logger.verbose('TIMER armed for %s'%self.show_time(timestamp))
155 logger.verbose('reservation.GetSlivers : end listing timers')