source: fedd/federation/emulab_segment.py @ c3a573c

Last change on this file since c3a573c was 26821ac, checked in by Ted Faber <faber@…>, 11 years ago

Hooks for shared NAT

  • Property mode set to 100755
File size: 7.5 KB
RevLine 
[181aeb4]1#!/usr/local/bin/python
2
[06c1dba]3import sys, os
4import re
[181aeb4]5
[06c1dba]6import tempfile
7import subprocess
8import logging 
9import time
10import signal
[1ae1aa2]11
[06c1dba]12import util
[181aeb4]13
[06c1dba]14from ssh_emulab_segment import ssh_emulab_segment
15from xmlrpc_emulab_segment import xmlrpc_emulab_segment
[181aeb4]16
17
[06c1dba]18class start_segment(ssh_emulab_segment, xmlrpc_emulab_segment):
19    def __init__(self, log=None, keyfile=None, debug=False, boss=None,
[c7141dc]20            ops=None, cert=None):
[06c1dba]21        ssh_emulab_segment.__init__(self, log=log, keyfile=keyfile, debug=debug)
[c7141dc]22        xmlrpc_emulab_segment.__init__(self, boss=boss, ops=ops, cert=cert)
[181aeb4]23
[06c1dba]24    def set_up_experiment_filespace(self, user, host, pid, eid, tmpdir):
[181aeb4]25        """
[06c1dba]26        Send all the software and configuration files into the experiment's
27        file space.  To reduce the number of ssh connections, we script many
28        changes and execute the script.
[181aeb4]29        """
[06c1dba]30        # Configuration directories on the remote machine
31        proj_dir = "/proj/%s/exp/%s/tmp" % (pid, eid)
[be1742d]32        softdir_root = "/proj/%s/software/" % pid
33        softdir = "%s/%s" % (softdir_root, eid)
[06c1dba]34        # Local software dir
35        lsoftdir = "%s/software" % tmpdir
36
37        # Open up a temporary file to contain a script for setting up the
38        # filespace for the new experiment.
39        self.log.info("[start_segment]: creating script file")
40        try:
41            sf, scriptname = tempfile.mkstemp()
42            scriptfile = os.fdopen(sf, 'w')
43        except EnvironmentError:
44            return False
[181aeb4]45
[06c1dba]46        scriptbase = os.path.basename(scriptname)
47
48        # Script the filesystem changes
[d4946da]49       
50        # Set umask to 007.  Since we are operating
51        # within /proj, we want to permit all proj users
52        # read and write.  This is especially necessary
53        # since creating directory hierarchy (mkdir -p).
54        print >>scriptfile, "umask 007"
[06c1dba]55        print >>scriptfile, "/bin/rm -rf %s" % proj_dir
56        # Clear and create the software directory
57        print >>scriptfile, "/bin/rm -rf %s/*" % softdir
[be1742d]58        print >>scriptfile, 'mkdir %s' % proj_dir
59        print >>scriptfile, 'chmod 0770 %s' % proj_dir
[06c1dba]60        if os.path.isdir(lsoftdir):
[be1742d]61            print >>scriptfile, 'mkdir %s' % softdir_root
62            print >>scriptfile, 'chmod 0770 %s' % softdir_root
63            print >>scriptfile, 'mkdir %s' % softdir
[9a256f7]64            print >>scriptfile, 'chmod 0770 %s' % softdir
[06c1dba]65        print >>scriptfile, "rm -f %s" % scriptbase
66        scriptfile.close()
67
68        # Move the script to the remote machine
69        # XXX: could collide tempfile names on the remote host
70        if self.scp_file(scriptname, user, host, scriptbase):
71            os.remove(scriptname)
[181aeb4]72        else:
[06c1dba]73            return False
[181aeb4]74
[06c1dba]75        # Execute the script (and the script's last line deletes it)
76        if not self.ssh_cmd(user, host, "sh -x %s" % scriptbase):
77            return False
[181aeb4]78
[06c1dba]79        for f in os.listdir(tmpdir):
80            if not os.path.isdir("%s/%s" % (tmpdir, f)):
81                if not self.scp_file("%s/%s" % (tmpdir, f), user, host,
82                        "%s/%s" % (proj_dir, f)):
83                    return False
84        if os.path.isdir(lsoftdir):
85            for f in os.listdir(lsoftdir):
86                if not os.path.isdir("%s/%s" % (lsoftdir, f)):
87                    if not self.scp_file("%s/%s" % (lsoftdir, f), 
88                            user, host, "%s/%s" % (softdir, f)):
89                        return False
90        return True
[181aeb4]91
92
[06c1dba]93    def __call__(self, parent, eid, pid, user, tclfile, tmpdir, timeout=0, 
94            gid=None):
[181aeb4]95        """
[06c1dba]96        Start a sub-experiment on a federant.
[181aeb4]97
[06c1dba]98        Get the current state, and terminate the experiment if it exists. The
99        group membership of the experiment is difficult to determine or change,
100        so start with a clean slate.  Create a new one and ship data
101        and configs and start the experiment.  There are small ordering
102        differences based on the initial state of the sub-experiment.
[05c41f5]103        """
104
[06c1dba]105        state = self.get_state(pid, eid)
[05c41f5]106
[06c1dba]107        if state != 'none':
108            self.terminate_exp(pid, eid)
[05c41f5]109
[06c1dba]110        if not self.make_null_experiment(pid, eid, tmpdir, gid):
111            return False
[6e33086]112
[c7141dc]113        if not self.set_up_experiment_filespace(user, self.ops, 
114                pid, eid, tmpdir):
[06c1dba]115            return False
[1ae1aa2]116
[06c1dba]117        # Put the file into a string to pass to emulab.
118        try:
119            tcl = "".join([ l for l in open(tclfile,"r")])
120        except EnvironmentError, e:
121            self.log.error("Can't read %s: %s" % (tclfile, e))
122            return False
123       
124        # Stage the new configuration
125        if not self.modify_exp(pid, eid, tcl):
126            self.log.error("modify failed")
127            return False
[1ae1aa2]128
[06c1dba]129        if not self.swap_exp(pid, eid, 'in'):
130            self.log.error("swap in failed")
131            return False
132        # Everything has gone OK.
133        self.get_mapping(pid,eid)
134        return True
[1ae1aa2]135
[c7141dc]136class stop_segment(ssh_emulab_segment, xmlrpc_emulab_segment):
[06c1dba]137    def __init__(self, log=None, keyfile=None, debug=False, boss=None, 
[c7141dc]138            ops=None, cert=None):
139        ssh_emulab_segment.__init__(self, log=log, keyfile=keyfile, debug=debug)
140        xmlrpc_emulab_segment.__init__(self, boss=boss, ops=ops, cert=cert)
[181aeb4]141
[06c1dba]142    def __call__(self, parent, user, pid, eid, gid=None, terminate=False):
[b709861]143        """
[06c1dba]144        Stop a sub experiment by calling swapexp on the federant
[b709861]145        """
146
[06c1dba]147        self.log.info("[stop_segment]: Stopping %s" % eid)
148        rv = False
149        try:
150            # Clean out tar files: we've gone over quota in the past
[c7141dc]151            self.ssh_cmd(user, self.ops, 
152                    "rm -rf /proj/%s/software/%s" % (pid, eid))
[06c1dba]153            rv = self.swap_exp(pid, eid, 'out')
154            if terminate:
155                rv = self.terminate_exp(pid, eid)
[5726f53]156        except self.ssh_cmd_timeout:
[06c1dba]157            rv = False
158        return rv
159
[c7141dc]160class info_segment(ssh_emulab_segment, xmlrpc_emulab_segment):
[06c1dba]161    def __init__(self, log=None, keyfile=None, debug=False, boss=None, 
[c7141dc]162            ops=None, cert=None):
163        ssh_emulab_segment.__init__(self, log=log, keyfile=keyfile, debug=debug)
164        xmlrpc_emulab_segment.__init__(self, boss=boss, ops=ops, cert=cert)
[06c1dba]165
166    def __call__(self, parent, user, pid, eid):
167        self.log.info("[info_segment]: Getting info from %s" % eid)
168        self.get_mapping(pid,eid)
169        return True
170
[c7141dc]171class operation_segment(ssh_emulab_segment, xmlrpc_emulab_segment):
[06c1dba]172    def __init__(self, log=None, keyfile=None, debug=False, boss=None, 
[c7141dc]173            ops=None, cert=None):
174        ssh_emulab_segment.__init__(self, log=log, keyfile=keyfile, debug=debug)
175        xmlrpc_emulab_segment.__init__(self, boss=boss, ops=ops, cert=cert)
[06c1dba]176
177    def __call__(self, parent, op, targets, param, top):
178        for l, p in targets.items():
179            self.log.info("[operation_segment]: Calling op %s on %s(%s)" % \
180                    (op, l,p))
181            self.do_operation(op, l, p, param, top)
182        return True
[26821ac]183
184class exports_segment(ssh_emulab_segment, xmlrpc_emulab_segment):
185    '''
186    Class to export parameters from this segment.  For a standard segment these
187    are calculated, so there is no testbed interaction.  For shared-NAT DETER
188    installations, this is more involved.  This class is a hook for that more
189    involved setup.
190    '''
191    def __init__(self, log=None, keyfile=None, debug=False, boss=None,
192            ops=None, cert=None):
193        ssh_emulab_segment.__init__(self, log=log, keyfile=keyfile, debug=debug)
194        xmlrpc_emulab_segment.__init__(self, boss=boss, ops=ops, cert=cert)
195
196    def __call__(self, parent, eid, pid, user, connInfo, tmpdir, timeout=0,
197            gid=None):
198        '''
199        Install the parameter values into each output parameter in each
200        connInfo entry.  This class understands peer and ssh_port output
201        variables.
202        '''
203
204        for c in connInfo:
205            for p in c.get('parameter', []):
206                # Only set output parameters
207                if  p.get('type', '') != 'output':
208                    continue
209                name = p.get('name', '')
210                # Debugging output
211                k = p.get('key', None)
212                if name == 'peer':
213                    if parent.nat_portal:
214                        value = parent.nat_portal
215                    elif k and k.index('/') != -1:
216                        value = "%s.%s.%s%s" % \
217                            (k[k.index('/')+1:], eid, pid, parent.domain)
218                    else:
219                        self.log.error("Bad export request: %s" % p)
220                        continue
221                    p['value'] = value
222                    self.log.debug("Assigning %s to %s" % (k, value))
223                elif name == 'ssh_port':
224                    value = parent.ssh_port
225                    p['value'] = value
226                    self.log.debug("Assigning %s to %s" % (k, value))
227                else:
228                    self.log.error("Unknown export parameter: %s" % \
229                            p.get('name'))
230                    continue
231        return True
Note: See TracBrowser for help on using the repository browser.