new SFA settings names (sfa_plc vs sfa_db)
[tests.git] / system / Substrate.py
index d8b0c02..1d42cb7 100644 (file)
@@ -69,6 +69,37 @@ def timestamp_sort(o1,o2): return o1.timestamp-o2.timestamp
 
 def short_hostname (hostname):
     return hostname.split('.')[0]
+
+####################
+# the place were other test instances tell about their not-yet-started
+# instances, that go undetected through sensing
+class Starting:
+
+    location='/root/starting'
+    def __init__ (self):
+        self.tuples=[]
+
+    def load (self):
+        try:    self.tuples=[line.strip().split('@') 
+                             for line in file(Starting.location).readlines()]
+        except: self.tuples=[]
+
+    def vnames (self) : 
+        self.load()
+        return [ x for (x,_) in self.tuples ]
+
+    def add (self, vname, bname):
+        if not vname in self.vnames():
+            file(Starting.location,'a').write("%s@%s\n"%(vname,bname))
+            
+    def delete_vname (self, vname):
+        self.load()
+        if vname in self.vnames():
+            f=file(Starting.location,'w')
+            for (v,b) in self.tuples: 
+                if v != vname: f.write("%s@%s\n"%(v,b))
+            f.close()
+    
 ####################
 # pool class
 # allows to pick an available IP among a pool
@@ -113,9 +144,11 @@ class PoolItem:
 
 class Pool:
 
-    def __init__ (self, tuples,message):
+    def __init__ (self, tuples,message, substrate):
         self.pool_items= [ PoolItem (hostname,userdata) for (hostname,userdata) in tuples ] 
         self.message=message
+        # where to send notifications upon load_starting
+        self.substrate=substrate
 
     def list (self):
         for i in self.pool_items: print i.line()
@@ -150,40 +183,34 @@ class Pool:
                 return (i.hostname,i.userdata)
         return None
 
-    # 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')
+    ####################
+    # we have a starting instance of our own
+    def add_starting (self, vname, bname):
+        Starting().add(vname,bname)
         for i in self.pool_items:
-            if i.hostname==name: i.status='mine'
-            
-    # we load this after actual sensing; 
+            if i.hostname==vname: i.status='mine'
+
+    # load the starting instances from the common file
+    # remember that might be ours
+    # return the list of (vname,bname) that are not ours
     def load_starting (self):
-        try:    items=[line.strip() for line in file(Pool.starting).readlines()]
-        except: items=[]
-        for i in self.pool_items:
-            if i.hostname in items:
-                if i.status=='free' : i.status='starting'
+        starting=Starting()
+        starting.load()
+        new_tuples=[]
+        for (v,b) in starting.tuples:
+            for i in self.pool_items:
+                if i.hostname==v and i.status=='free':
+                    i.status='starting'
+                    new_tuples.append( (v,b,) )
+        return new_tuples
 
     def release_my_starting (self):
         for i in self.pool_items:
-            if i.status=='mine': 
-                self.del_starting(i.hostname)
+            if i.status=='mine':
+                Starting().delete_vname (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()
-    
+
     ##########
     def _sense (self):
         for item in self.pool_items:
@@ -201,10 +228,10 @@ class Pool:
         print 'Sensing IP pool',self.message,
         self._sense()
         print 'Done'
-        self.load_starting()
+        for (vname,bname) in self.load_starting():
+            self.substrate.add_starting_dummy (bname, vname)
         print 'After starting: IP pool'
         print self.line()
-
     # OS-dependent ping option (support for macos, for convenience)
     ping_timeout_option = None
     # returns True when a given hostname/ip responds to ping
@@ -277,6 +304,9 @@ class Box:
         if not self._probed: print "root@%s unreachable"%self.hostname
         return self._probed
 
+    # use argv=['bash','-c',"the command line"]
+    # if you have any shell-expanded arguments like *
+    # and if there's any chance the command is adressed to the local host
     def backquote_ssh (self, argv, trash_err=False):
         if not self.probe(): return ''
         return self.backquote( self.test_ssh().actual_argv(argv), trash_err)
@@ -448,9 +478,11 @@ class PlcBox (Box):
             if not vserver_line: continue
             context=vserver_line.split()[0]
             if context=="CTX": continue
-            longname=ctx_dict[context]
-            self.add_vserver(longname,context)
-#            print self.margin_outline(self.vplcname(longname)),"%(vserver_line)s [=%(longname)s]"%locals()
+            try:
+                longname=ctx_dict[context]
+                self.add_vserver(longname,context)
+            except:
+                print 'WARNING: found ctx %s in vserver_stat but was unable to figure a corresp. vserver'%context
 
         # scan timestamps 
         running_vsnames = [ i.vservername for i in self.plc_instances ]
@@ -608,6 +640,7 @@ class QemuBox (Box):
                 live_builds.append(buildname)
             except: print 'WARNING, could not parse pid line',pid_line
         # retrieve timestamps
+        if not live_builds: return
         command=   ['grep','.']
         command += ['%s/*/timestamp'%b for b in live_builds]
         command += ['/dev/null']
@@ -675,7 +708,7 @@ class TestBox (Box):
         # can't reboot a vserver VM
         self.run_ssh (['pkill','run_log'],"Terminating current runs",
                       dry_run=options.dry_run)
-        self.run_ssh (['rm','-f',Pool.starting],"Cleaning %s"%Pool.starting,
+        self.run_ssh (['rm','-f',Starting.location],"Cleaning %s"%Starting.location,
                       dry_run=options.dry_run)
 
     def get_test (self, buildname):
@@ -713,14 +746,13 @@ class TestBox (Box):
     def sense (self, options):
         print 't',
         self.sense_uptime()
-        self.starting_ips=[x for x in self.backquote_ssh(['cat',Pool.starting], trash_err=True).strip().split('\n') if x]
+        self.starting_ips=[x for x in self.backquote_ssh(['cat',Starting.location], trash_err=True).strip().split('\n') if x]
 
         # scan timestamps on all tests
         # this is likely to not invoke ssh so we need to be a bit smarter to get * expanded
         # xxx would make sense above too
         command=['bash','-c',"grep . /root/*/timestamp /dev/null"]
-        #ts_lines=self.backquote_ssh(command,trash_err=True).split('\n')
-        ts_lines=self.backquote_ssh(command).split('\n')
+        ts_lines=self.backquote_ssh(command,trash_err=True).split('\n')
         for ts_line in ts_lines:
             if not ts_line.strip(): continue
             # expect /root/<buildname>/timestamp:<timestamp>
@@ -788,11 +820,12 @@ class Substrate:
         self.build_boxes = [ BuildBox(h) for h in self.build_boxes_spec() ]
         self.plc_boxes = [ PlcBox (h,m) for (h,m) in self.plc_boxes_spec ()]
         self.qemu_boxes = [ QemuBox (h,m) for (h,m) in self.qemu_boxes_spec ()]
-        self.all_boxes = self.plc_boxes + self.qemu_boxes
+        self.default_boxes = self.plc_boxes + self.qemu_boxes
+        self.all_boxes = self.build_boxes + [ self.test_box ] + self.plc_boxes + self.qemu_boxes
         self._sensed=False
 
-        self.vplc_pool = Pool (self.vplc_ips(),"for vplcs")
-        self.vnode_pool = Pool (self.vnode_ips(),"for vnodes")
+        self.vplc_pool = Pool (self.vplc_ips(),"for vplcs",self)
+        self.vnode_pool = Pool (self.vnode_ips(),"for vnodes",self)
 
     def fqdn (self, hostname):
         if hostname.find('.')<0: return "%s.%s"%(hostname,self.domain())
@@ -802,23 +835,28 @@ class Substrate:
     def sense (self,force=False):
         if self._sensed and not force: return False
         print 'Sensing local substrate...',
-        for b in self.all_boxes: b.sense(self.options)
+        for b in self.default_boxes: b.sense(self.options)
         print 'Done'
         self._sensed=True
         return True
 
     def list (self):
-        for b in self.all_boxes:
+        for b in self.default_boxes:
             b.list()
 
     def add_dummy_plc (self, plc_boxname, plcname):
         for pb in self.plc_boxes:
             if pb.hostname==plc_boxname:
                 pb.add_dummy(plcname)
+                return True
     def add_dummy_qemu (self, qemu_boxname, qemuname):
         for qb in self.qemu_boxes:
             if qb.hostname==qemu_boxname:
                 qb.add_dummy(qemuname)
+                return True
+
+    def add_starting_dummy (self, bname, vname):
+        return self.add_dummy_plc (bname, vname) or self.add_dummy_qemu (bname, vname)
 
     ########## 
     def provision (self,plcs,options):
@@ -829,6 +867,7 @@ class Substrate:
             plcs = [ self.provision_qemus (plc,options) for plc in plcs ]
             # update the SFA spec accordingly
             plcs = [ self.localize_sfa_rspec(plc,options) for plc in plcs ]
+            self.list()
             return plcs
         except Exception, e:
             print '* Could not provision this test on current substrate','--',e,'--','exiting'
@@ -905,7 +944,7 @@ class Substrate:
         # 
         self.add_dummy_plc(plc_boxname,plc['name'])
         vplc_ip = self.vplc_pool.get_ip(vplc_hostname)
-        self.vplc_pool.add_starting(vplc_hostname)
+        self.vplc_pool.add_starting(vplc_hostname, plc_boxname)
 
         #### compute a helpful vserver name
         # remove domain in hostname
@@ -995,10 +1034,10 @@ class Substrate:
                         vnode_hostname=freed_vnode_hostname
                         self.vnode_pool.set_mine(vnode_hostname)
 
-            self.add_dummy_qemu (qemu_boxname,nodename)
+            self.add_dummy_qemu (qemu_boxname,vnode_hostname)
             mac=self.vnode_pool.retrieve_userdata(vnode_hostname)
             ip=self.vnode_pool.get_ip (vnode_hostname)
-            self.vnode_pool.add_starting(vnode_hostname)
+            self.vnode_pool.add_starting(vnode_hostname,qemu_boxname)
 
             vnode_fqdn = self.fqdn(vnode_hostname)
             nodemap={'host_box':qemu_boxname,
@@ -1019,11 +1058,8 @@ class Substrate:
         plc['sfa']['SFA_REGISTRY_HOST'] = plc['PLC_DB_HOST']
         plc['sfa']['SFA_AGGREGATE_HOST'] = plc['PLC_DB_HOST']
         plc['sfa']['SFA_SM_HOST'] = plc['PLC_DB_HOST']
-        plc['sfa']['SFA_PLC_DB_HOST'] = plc['PLC_DB_HOST']
+        plc['sfa']['SFA_DB_HOST'] = plc['PLC_DB_HOST']
         plc['sfa']['SFA_PLC_URL'] = 'https://' + plc['PLC_API_HOST'] + ':443/PLCAPI/' 
-        for site in plc['sites']:
-            for node in site['nodes']:
-                plc['sfa']['sfa_slice_rspec']['part4'] = node['node_fields']['hostname']
        return plc
 
     #################### release:
@@ -1040,23 +1076,23 @@ class Substrate:
         print "Could not find box %s"%boxname
         return None
 
-    def list_boxes(self,boxnames):
+    def list_boxes(self,box_or_names):
         print 'Sensing',
-        for boxname in boxnames:
-            b=self.get_box(boxname)
-            if not b: continue
-            b.sense(self.options)
+        for box in box_or_names:
+            if not isinstance(box,Box): box=self.get_box(box)
+            if not box: continue
+            box.sense(self.options)
         print 'Done'
-        for boxname in boxnames:
-            b=self.get_box(boxname)
-            if not b: continue
-            b.list()
+        for box in box_or_names:
+            if not isinstance(box,Box): box=self.get_box(box)
+            if not box: continue
+            box.list()
 
-    def reboot_boxes(self,boxnames):
-        for boxname in boxnames:
-            b=self.get_box(boxname)
-            if not b: continue
-            b.reboot(self.options)
+    def reboot_boxes(self,box_or_names):
+        for box in box_or_names:
+            if not isinstance(box,Box): box=self.get_box(box)
+            if not box: continue
+            box.reboot(self.options)
 
     ####################
     # can be run as a utility to manage the local infrastructure
@@ -1074,6 +1110,8 @@ class Substrate:
                            help='add plc boxes')
         parser.add_option ('-q',"--qemu",action='store_true',dest='qemus',default=False,
                            help='add qemu boxes') 
+        parser.add_option ('-a',"--all",action='store_true',dest='all',default=False,
+                           help='address all known  boxes, like -b -t -p -q')
         parser.add_option ('-v',"--verbose",action='store_true',dest='verbose',default=False,
                            help='verbose mode')
         parser.add_option ('-n',"--dry_run",action='store_true',dest='dry_run',default=False,
@@ -1081,16 +1119,15 @@ class Substrate:
         (self.options,args)=parser.parse_args()
 
         boxes=args
-        if self.options.testbox: boxes += [self.test_box.hostname]
-        if self.options.builds: boxes += [b.hostname for b in self.build_boxes]
-        if self.options.plcs: boxes += [b.hostname for b in self.plc_boxes]
-        if self.options.qemus: boxes += [b.hostname for b in self.qemu_boxes]
-        boxes=list(set(boxes))
+        if self.options.testbox: boxes += [self.test_box]
+        if self.options.builds: boxes += self.build_boxes
+        if self.options.plcs: boxes += self.plc_boxes
+        if self.options.qemus: boxes += self.qemu_boxes
+        if self.options.all: boxes += self.all_boxes
         
-        # default scope
+        # default scope is -b -p -q
         if not boxes:
-            boxes = [ b.hostname for b in \
-                          self.build_boxes + self.plc_boxes + self.qemu_boxes ]
+            boxes = self.build_boxes + self.plc_boxes + self.qemu_boxes
 
         if self.options.reboot: self.reboot_boxes (boxes)
         else:                   self.list_boxes (boxes)