Ignore:
Timestamp:
May 28, 2010 3:16:46 AM (14 years ago)
Author:
Ted Faber <faber@…>
Branches:
axis_example, compt_changes, info-ops, master, version-3.01, version-3.02
Children:
2f6820c
Parents:
06cc65b
Message:

More refactoring. Neaten up the code for creating segments in emulab and make the local and proxy class structures parallel. The code is more readable this way, I hope.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • fedd/federation/local_emulab_segment.py

    r06cc65b r5bf359d  
    1212import util
    1313
    14 class local_emulab_segment:
    15     class cmd_timeout(RuntimeError): pass
    16 
     14from local_segment import local_segment
     15
     16class start_segment(local_segment):
    1717    def __init__(self, log=None, keyfile=None, debug=False):
    18         self.log = log or logging.getLogger(\
    19                 'fedd.access.proxy_emulab_segment')
    20         self.certfile = keyfile
    21         self.debug = debug
    22         self.cmd_timeout = local_emulab_segment.cmd_timeout
    23 
    24     def copy_file(self, src, dest, size=1024):
    25         """
    26         Exceedingly simple file copy.
    27         """
    28 
    29         if not self.debug:
    30             util.copy_file(src, dest, size)
    31         else:
    32             self.log.debug("Copy %s to %s" % (src, dest))
    33 
    34     def cmd_with_timeout(self, cmd, wname=None, timeout=None):
    35         """
    36         Run a command.  If debug is set, the action
    37         is only logged.  Commands are run without stdin, to avoid stray
    38         SIGTTINs. If timeout is given and the command runs longer, a
    39         cmd_timeout exception is thrown.
    40         """
    41 
    42         try:
    43             dnull = open("/dev/null", "w")
    44         except EnvironmentError:
    45             self.log.debug("[cmd_with_timeout]: failed to open /dev/null " + \
    46                     "for redirect")
    47             dnull = Null
    48 
    49         self.log.debug("[cmd_with_timeout]: %s" % cmd)
    50         if not self.debug:
    51             if dnull:
    52                 sub = subprocess.Popen(cmd, shell=True, stdout=dnull,
    53                         stderr=dnull, close_fds=True)
    54             else:
    55                 sub = subprocess.Popen(cmd, shell=True, close_fds=True)
    56             if timeout:
    57                 i = 0
    58                 rv = sub.poll()
    59                 while i < timeout:
    60                     if rv is not None: break
    61                     else:
    62                         time.sleep(1)
    63                         rv = sub.poll()
    64                         i += 1
    65                 else:
    66                     self.log.debug("Process exceeded runtime: %s" % cmd)
    67                     os.kill(sub.pid, signal.SIGKILL)
    68                     raise self.cmd_timeout();
    69                 return rv == 0
    70             else:
    71                 return sub.wait() == 0
    72         else:
    73             if timeout == 0:
    74                 self.log.debug("debug timeout raised on %s " % cmd)
    75                 raise self.cmd_timeout()
    76             else:
    77                 return True
    78 
    79 class start_segment(local_emulab_segment):
    80     def __init__(self, log=None, keyfile=None, debug=False):
    81         local_emulab_segment.__init__(self, log=log,
    82                 keyfile=keyfile, debug=debug)
     18        local_segment.__init__(self, log=log, keyfile=keyfile, debug=debug)
    8319        self.null = """
    8420set ns [new Simulator]
     
    9329
    9430    def get_state(self, pid, eid):
     31        """
     32        Return the state of the experiment as reported by emulab
     33        """
    9534        # command to test experiment state
    9635        expinfo_exec = "/usr/testbed/bin/expinfo" 
     
    14180
    14281    def get_mapping(self, pid, eid):
     82        """
     83        Get the physical to virtual mapping from the expinfo command and save
     84        it in the self.map member.
     85        """
    14386        # command to test experiment state
    14487        expinfo_exec = "/usr/testbed/bin/expinfo" 
     
    199142            return True
    200143
    201 
    202 
    203     def __call__(self, parent, eid, pid, user, tclfile, tmpdir, timeout=0):
    204         """
    205         Start a sub-experiment on a federant.
    206 
    207         Get the current state, modify or create as appropriate, ship data
    208         and configs and start the experiment.  There are small ordering
    209         differences based on the initial state of the sub-experiment.
    210         """
     144    def make_null_experiment(self, pid, eid, tmpdir):
     145        """
     146        Create a null copy of the experiment so that we capture any logs there
     147        if the modify fails.  Emulab software discards the logs from a failed
     148        startexp.
     149        """
     150        try:
     151            f = open("%s/null.tcl" % tmpdir, "w")
     152            print >>f, self.null
     153            f.close()
     154        except EnvironmentError, e:
     155            raise service_error(service_error.internal,
     156                    "Cannot stage null.tcl: %s" % e.strerror)
     157
     158        timedout = False
     159        try:
     160            if not self.cmd_with_timeout(
     161                    ("/usr/testbed/bin/startexp -i -f -w -p %s " +
     162                    "-e %s %s/null.tcl") % (pid, eid, tmpdir), "startexp",
     163                    timeout=60 * 10):
     164                return False
     165        except self.cmd_timeout:
     166            timedout = True
     167
     168        if timedout:
     169            state = self.get_state(pid, eid)
     170            return state == "swapped"
     171        else:
     172            return True
     173
     174    def set_up_experiment_filespace(self, pid, eid, tmpdir):
    211175        # Configuration directories on this machine
    212176        proj_dir = "/proj/%s/exp/%s/tmp" % (pid, eid)
     
    215179        lsoftdir = "%s/software" % tmpdir
    216180
    217         state = self.get_state(pid, eid)
    218 
    219         if state == 'none':
    220             # Create a null copy of the experiment so that we capture any
    221             # logs there if the modify fails.  Emulab software discards the
    222             # logs from a failed startexp
    223             try:
    224                 f = open("%s/null.tcl" % tmpdir, "w")
    225                 print >>f, self.null
    226                 f.close()
    227             except EnvironmentError, e:
    228                 raise service_error(service_error.internal,
    229                         "Cannot stage null.tcl: %s" % e.strerror)
    230 
    231             timedout = False
    232             try:
    233                 if not self.cmd_with_timeout(
    234                         ("/usr/testbed/bin/startexp -i -f -w -p %s " +
    235                         "-e %s %s/null.tcl") % (pid, eid, tmpdir), "startexp",
    236                         timeout=60 * 10):
    237                     return False
    238             except self.cmd_timeout:
    239                 timedout = True
    240 
    241             if timedout:
    242                 state = self.get_state(pid, eid)
    243                 if state != "swapped":
    244                     return False
    245        
    246181        # Set up the experiment's file space
    247182        if not self.cmd_with_timeout("/bin/rm -rf %s" % proj_dir):
     
    270205            return False
    271206
     207        return True
     208
     209    def swap_in(self, pid, eid):
     210        """
     211        Swap experiment in.  This includes code to cope with the experiment
     212        swaping command timing out, but the experiment being swapped in
     213        successfully.
     214        """
     215        self.log.info("[start_segment]: Swapping %s" % eid)
     216        timedout = False
     217        try:
     218            if not self.cmd_with_timeout(
     219                    "/usr/testbed/bin/swapexp -w %s %s in" % (pid, eid),
     220                    "swapexp", timeout=25*60):
     221                return False
     222        except self.cmd_timeout:
     223            timedout = True
     224       
     225        # If the command was terminated, but completed successfully,
     226        # report success.
     227        if timedout:
     228            self.log.debug("[start_segment]: swapin timed out " +\
     229                    "checking state")
     230            state = self.get_state(pid, eid)
     231            self.log.debug("[start_segment]: state is %s" % state)
     232            return state == 'active'
     233        else:
     234            return True
     235
     236    def __call__(self, parent, eid, pid, user, tclfile, tmpdir, timeout=0):
     237        """
     238        Start a sub-experiment on a federant.
     239
     240        Get the current state, modify or create as appropriate, ship data
     241        and configs and start the experiment.  There are small ordering
     242        differences based on the initial state of the sub-experiment.
     243        """
     244
     245        state = self.get_state(pid, eid)
     246
     247        if state == 'none':
     248            if not self.make_null_experiment(pid, eid, tmpdir):
     249                return False
     250
     251        if not self.set_up_experiment_filespace(pid, eid, tmpdir):
     252            return False
     253       
    272254        # Stage the new configuration (active experiments will stay swapped
    273255        # in now)
     
    286268        # Active experiments are still swapped, this swaps the others in.
    287269        if state != 'active':
    288             self.log.info("[start_segment]: Swapping %s" % eid)
    289             timedout = False
    290             try:
    291                 if not self.cmd_with_timeout(
    292                         "/usr/testbed/bin/swapexp -w %s %s in" % (pid, eid),
    293                         "swapexp", timeout=25*60):
    294                     return False
    295             except self.cmd_timeout:
    296                 timedout = True
    297            
    298             # If the command was terminated, but completed successfully,
    299             # report success.
    300             if timedout:
    301                 self.log.debug("[start_segment]: swapin timed out " +\
    302                         "checking state")
    303                 state = self.get_state(pid, eid)
    304                 self.log.debug("[start_segment]: state is %s" % state)
    305                 if state != 'active':
    306                     return False
     270            if not self.swap_in(pid, eid):
     271                return False
    307272        # Everything has gone OK.
    308273        self.get_mapping(pid,eid)
    309274        return True
    310275
    311 class stop_segment(local_emulab_segment):
     276class stop_segment(local_segment):
    312277    def __init__(self, log=None, keyfile=None, debug=False):
    313         local_emulab_segment.__init__(self,
    314                 log=log, keyfile=keyfile, debug=debug)
     278        local_segment.__init__(self, log=log, keyfile=keyfile, debug=debug)
    315279
    316280    def __call__(self, parent, user, pid, eid):
Note: See TracChangeset for help on using the changeset viewer.