# . and their admissible load (max # of myplcs)
# . the pool of DNS-names and IP-addresses available for nodes
#
+# #################### implem. note
+#
+# this model relies on 'sensing' the substrate,
+# i.e. probing all the boxes for their running instances of vservers and qemu
+# this is how we get rid of tracker inconsistencies
+# however there is a 'black hole' between the time where a given address is
+# allocated and when it actually gets used/pingable
+# this is why we still need a shared knowledge among running tests
+# in a file named /root/starting
+# this is connected to the Pool class
+#
# ####################
import os.path, sys
def __init__ (self,hostname,userdata):
self.hostname=hostname
self.userdata=userdata
- # slot holds 'busy' or 'free' or 'fake' or None
+ # slot holds 'busy' or 'free' or 'mine' or 'starting' or None
+ # 'mine' is for our own stuff, 'starting' from the concurrent tests
self.status=None
self.ip=None
def __init__ (self, tuples,message):
self.pool= [ PoolItem (h,u) for (h,u) in tuples ]
self.message=message
- self._sensed=False
def sense (self):
- if self._sensed: return
print 'Checking IP pool',self.message,
for item in self.pool:
- if self.check_ping (item.hostname): item.status='busy'
- else: item.status='free'
- self._sensed=True
+ if item.status is not None:
+ continue
+ if self.check_ping (item.hostname):
+ item.status='busy'
+ else:
+ item.status='free'
print 'Done'
def list (self):
def next_free (self):
for i in self.pool:
- if i.status in ['busy','fake']: continue
- i.status='fake'
- return (i.hostname,i.userdata)
+ if i.status == 'free':
+ i.status='mine'
+ return (i.hostname,i.userdata)
raise Exception,"No IP address available in pool %s"%self.message
-# OS-dependent ping option (support for macos, for convenience)
+ # OS-dependent ping option (support for macos, for convenience)
ping_timeout_option = None
-# checks whether a given hostname/ip responds to ping
+ # checks whether a given hostname/ip responds to ping
def check_ping (self,hostname):
if not Pool.ping_timeout_option:
(status,osname) = commands.getstatusoutput("uname -s")
else: print '-',
return status == 0
+ # the place were other test instances tell about their not-yet-started
+ # instances, that go undetected through sensing
+ starting='/root/starting'
+ def add_starting (self, name):
+ try: items=[line.strip() for line in file(Pool.starting).readlines()]
+ except: items=[]
+ if not name in items:
+ file(Pool.starting,'a').write(name+'\n')
+ for i in self.pool:
+ if i.hostname==name: i.status='mine'
+
+ def load_starting (self):
+ try: items=[line.strip() for line in file(Pool.starting).readlines()]
+ except: items=[]
+ for item in items:
+ for i in self.pool:
+ if i.hostname==item and i.status==None: i.status='starting'
+
+ def release_my_starting (self):
+ for i in self.pool:
+ if i.status=='mine':
+ self.del_starting(i.hostname)
+ i.status=None
+
+ def del_starting (self, name):
+ try: items=[line.strip() for line in file(Pool.starting).readlines()]
+ except: items=[]
+ if name in items:
+ f=file(Pool.starting,'w')
+ for item in items:
+ if item != name: f.write(item+'\n')
+ f.close()
+
####################
class Box:
def __init__ (self,hostname):
self.plc_instances.remove(plc_instance)
# fill one slot even though this one is not started yet
- def add_fake (self, plcname):
- fake=PlcInstance('fake_'+plcname,0,self)
- fake.set_now()
- self.plc_instances.append(fake)
+ def add_dummy (self, plcname):
+ dummy=PlcInstance('dummy_'+plcname,0,self)
+ dummy.set_now()
+ self.plc_instances.append(dummy)
def line(self):
msg="%s [max=%d,%d free] (%s)"%(self.hostname, self.max_plcs,self.free_spots(),self.uname())
# print self.margin_outline(self.vplcname(longname)),"%(vserver_line)s [=%(longname)s]"%locals()
# scan timestamps
+ running_ctx_ids = [ i.ctxid for i in self.plc_instances ]
command= ['grep','.']
- command += ['/vservers/%s/timestamp'%b for b in ctx_dict.values()]
+ command += ['/vservers/%s/timestamp'%b for b in running_ctx_ids]
command += ['/dev/null']
ts_lines=self.backquote_ssh(command,trash_err=True).split('\n')
for ts_line in ts_lines:
q=self.plc_instance_by_vservername(vservername)
if not q:
print 'WARNING unattached plc instance',ts_line
+ print 'was expeting to find',vservername,'in',[i.vservername for i in self.plc_instances]
continue
q.set_timestamp(timestamp)
except: print 'WARNING, could not parse ts line',ts_line
self.qemu_instances.remove(qemu_instance)
# fill one slot even though this one is not started yet
- def add_fake (self, nodename):
- fake=QemuInstance('fake_'+nodename,0,self)
- fake.set_now()
- self.qemu_instances.append(fake)
+ def add_dummy (self, nodename):
+ dummy=QemuInstance('dummy_'+nodename,0,self)
+ dummy.set_now()
+ self.qemu_instances.append(dummy)
def line (self):
msg="%s [max=%d,%d free] (%s)"%(self.hostname, self.max_qemus,self.free_spots(),self.driver())
self.vplc_pool = Pool (self.vplc_ips(),"for vplcs")
self.vnode_pool = Pool (self.vnode_ips(),"for vnodes")
- self.vnode_pool.list()
-
-
# def build_box_names (self):
# return [ h for h in self.build_boxes_spec() ]
# def plc_boxes (self):
plc_instance_to_kill.plc_box.hostname)
utils.header( 'plc %s -> box %s'%(plc['name'],plc_box.line()))
- plc_box.add_fake(plc['name'])
+ plc_box.add_dummy(plc['name'])
#### OK we have a box to run in, let's find an IP address
# look in options
if options.ips_vplc:
vplc_hostname=options.ips_vplc.pop()
else:
self.vplc_pool.sense()
+ self.vplc_pool.load_starting()
(vplc_hostname,unused)=self.vplc_pool.next_free()
vplc_ip = self.vplc_pool.get_ip(vplc_hostname)
+ self.vplc_pool.add_starting(vplc_hostname)
#### compute a helpful vserver name
# remove domain in hostname
#### apply in the plc_spec
# # informative
# label=options.personality.replace("linux","")
- mapper = {'plc': [ ('*' , {'hostname':plc_box.hostname,
+ mapper = {'plc': [ ('*' , {'host_box':plc_box.hostname,
# 'name':'%s-'+label,
'name': plc_name,
'vservername':vservername,
qemu_instance_to_kill.qemu_box.hostname)
utils.header( 'node %s -> qemu box %s'%(nodename,qemu_box.line()))
- qemu_box.add_fake(nodename)
+ qemu_box.add_dummy(nodename)
#### OK we have a box to run in, let's find an IP address
# look in options
if options.ips_vnode:
- qemu_hostname=options.ips_vnode.pop()
- mac=self.vnode_pool.retrieve_userdata(qemu_hostname)
- print 'case 1 hostname',qemu_hostname,'mac',mac
+ vnode_hostname=options.ips_vnode.pop()
+ mac=self.vnode_pool.retrieve_userdata(vnode_hostname)
else:
self.vnode_pool.sense()
- (qemu_hostname,mac)=self.vnode_pool.next_free()
- print 'case 2 hostname',qemu_hostname,'mac',mac
- ip=self.vnode_pool.get_ip (qemu_hostname)
- utils.header("Attaching %s on IP %s MAC %s"%(plc['name'],qemu_hostname,mac))
+ self.vnode_pool.load_starting()
+ (vnode_hostname,mac)=self.vnode_pool.next_free()
+ ip=self.vnode_pool.get_ip (vnode_hostname)
+ self.vnode_pool.add_starting(vnode_hostname)
- if qemu_hostname.find('.')<0:
- qemu_hostname += "."+self.domain()
+ if vnode_hostname.find('.')<0:
+ vnode_hostname += "."+self.domain()
nodemap={'host_box':qemu_box.hostname,
- 'node_fields:hostname':qemu_hostname,
+ 'node_fields:hostname':vnode_hostname,
'interface_fields:ip':ip,
'interface_fields:mac':mac,
}
nodemap.update(self.network_settings())
maps.append ( (nodename, nodemap) )
+ utils.header("Attaching %s on IP %s MAC %s"%(plc['name'],vnode_hostname,mac))
+
return test_mapper.map({'node':maps})[0]
def localize_sfa_rspec (self,plc,options):
plc['sfa']['sfa_slice_rspec']['part4'] = node['node_fields']['hostname']
return plc
+ #################### release:
+ def release (self,options):
+ self.vplc_pool.release_my_starting()
+ self.vnode_pool.release_my_starting()
+ pass
+
#################### show results for interactive mode
def list_all (self):
self.sense()