source: fedd/federation/proxy_protogeni_segment.py @ f432e51

axis_examplecompt_changesinfo-opsversion-3.01version-3.02
Last change on this file since f432e51 was d3c8759, checked in by Ted Faber <faber@…>, 15 years ago

Wholesale change of IOError to EnvironmentError? for file operations. Lots of
uncaught EnvironmentErrors? were causing spurious error conditions, e.g. on disk
full.

  • Property mode set to 100644
File size: 22.6 KB
RevLine 
[c119839]1#!/usr/local/bin/python
2
3import sys, os
4import re
5
6import tempfile
7import subprocess
8import logging 
9import time
10import random
11import string
12import signal
13
14import xml.parsers.expat
15from threading import Thread
16
17from proxy_segment import proxy_segment
18from service_error import service_error
19from remote_service import service_caller
20from util import fedd_ssl_context
21
22import topdl
23
24class segment_base(proxy_segment):
25    class ProtoGENIError(Exception): 
26        def __init__(self, op, code, output):
27            Exception.__init__(self, output)
28            self.op = op
29            self.code = code
30            self.output = output
31
32    def __init__(self, log=None, keyfile=None, debug=False, 
33            ch_url=None, sa_url=None, cm_url=None):
34        proxy_segment.__init__(self, log=log, keyfile=keyfile, debug=debug)
35
36        self.ProtoGENIError = start_segment.ProtoGENIError
37        self.ch_url = ch_url
38        self.sa_url = sa_url
39        self.cm_url = cm_url
40
41        self.call_SetValue = service_caller('SetValue')
42
43        self.debug_fail = ['Resolve']
44        self.debug_response = {
45                'RedeemTicket': ("XML blob1", "XML blob2"),
46                'SliceStatus': { 'status': 'ready' },
47            }
48
49
50    def pg_call(self, url, method, params, context):
[593e901]51        max_retries = 5
52        retries = 0
53
[c119839]54        s = service_caller(method, request_body_name="", strict=False)
55        self.log.debug("Calling %s %s" % (url, method))
56        if not self.debug:
[593e901]57            while retries < max_retries:
58                r = s.call_xmlrpc_service(url, params, context=context)
59                code = r.get('code', -1)
60                if code == 0:
61                    # Success leaves the loop here
62                    return r.get('value', None)
63                elif code == 14 and retries +1 < max_retries:
64                    # Busy resource
65                    retries+= 1
66                    self.log.info("Resource busy, retrying in 30 secs")
67                    time.sleep(30)
68                else:
69                    # NB: out of retries falls through to here
70                    raise self.ProtoGENIError(op=method, 
71                            code=r.get('code', 'unknown'), 
72                            output=r.get('output', 'No output'))
[c119839]73        else:
74            if method in self.debug_fail:
75                raise self.ProtoGENIError(op=method, code='unknown',
76                        output='No output')
77            elif self.debug_response.has_key(method):
78                return self.debug_response[method]
79            else:
80                return "%s XML blob" % method
81
82
83class start_segment(segment_base):
84    def __init__(self, log=None, keyfile=None, debug=False, 
85            ch_url=None, sa_url=None, cm_url=None):
86        segment_base.__init__(self, log=log, keyfile=keyfile, debug=debug,
87                ch_url=cm_url, sa_url=sa_url, cm_url=cm_url)
[b4b19c7]88        self.node = { }
[c119839]89
90
91    # Turn the manifest into a dict were each virtual nodename (i.e. the topdl
92    # name) has an entry with the allocated machine in hostname and the
93    # interfaces in 'interfaces'.  I love having XML parser code lying around.
[dd3e38b]94    def manifest_to_dict(self, manifest, ignore_debug=False):
95        if self.debug and not ignore_debug: 
[593e901]96            self.log.debug("Returning null manifest dict")
97            return { }
[c119839]98
99        # The class allows us to keep a little state - the dict under
100        # consteruction and the current entry in that dict for the interface
101        # element code.
102        class manifest_parser:
103            def __init__(self):
104                self.d = { }
105                self.current_key=None
106
107            # If the element is a node, create a dict entry for it.  If it's an
108            # interface inside a node, add an entry in the interfaces list with
109            # the virtual name and component id.
110            def start_element(self, name, attrs):
111                if name == 'node':
112                    self.current_key = attrs.get('virtual_id',"")
113                    if self.current_key:
114                        self.d[self.current_key] = {
115                                'hostname': attrs.get('hostname', None),
116                                'interfaces': { }
117                                }
118                elif name == 'interface' and self.current_key:
119                    self.d[self.current_key]['interfaces']\
120                            [attrs.get('virtual_id','')] = \
121                            attrs.get('component_id', None)
122            #  When a node is finished, clear current_key
123            def end_element(self, name):
124                if name == 'node': self.current_key = None
125
126
127        mp = manifest_parser()
128        p = xml.parsers.expat.ParserCreate()
129        # These are bound to the class we just created
130        p.StartElementHandler = mp.start_element
131        p.EndElementHandler = mp.end_element
132
133        p.Parse(manifest)
[b4b19c7]134        # Make the node dict that the callers expect
135        for k in mp.d:
136            self.node[k] = mp.d.get('hostname', '')
[c119839]137        return mp.d
138
139
[593e901]140    def generate_portal_configs(self, parent, topo, pubkey_base, 
141            secretkey_base, tmpdir, master, leid, connInfo, services, nodes):
142
143        def conninfo_to_dict(key, info):
144            """
145            Make a cpoy of the connection information about key, and flatten it
146            into a single dict by parsing out any feddAttrs.
147            """
148
149            rv = None
150            for i in info:
151                if key == i.get('portal', "") or \
152                        key in [e.get('element', "") \
153                        for e in i.get('member', [])]:
154                    rv = i.copy()
155                    break
156
157            else:
158                return rv
159
160            if 'fedAttr' in rv:
161                for a in rv['fedAttr']:
162                    attr = a.get('attribute', "")
163                    val = a.get('value', "")
164                    if attr and attr not in rv:
165                        rv[attr] = val
166                del rv['fedAttr']
167            return rv
168
169        # XXX: un hardcode this
170        def client_null(f, s):
171            print >>f, "Service: %s" % s['name']
172
173        def client_smb(f, s):
174            print >>f, "Service: %s" % s['name']
175            smbshare = None
176            smbuser = None
177            smbproj = None
178            for a in s.get('fedAttr', []):
179                if a.get('attribute', '') == 'SMBSHARE':
180                    smbshare = a.get('value', None)
181                elif a.get('attribute', '') == 'SMBUSER':
182                    smbuser = a.get('value', None)
183                elif a.get('attribute', '') == 'SMBPROJ':
184                    smbproj = a.get('value', None)
185
186            if all((smbshare, smbuser, smbproj)):
187                print >>f, "SMBshare: %s" % smbshare
188                print >>f, "ProjectUser: %s" % smbuser
189                print >>f, "ProjectName: %s" % smbproj
190
191        client_service_out = {
192                'SMB': client_smb,
193                'tmcd': client_null,
194                'seer': client_null,
195                'userconfig': client_null,
196            }
[9b3627e]197
198        def server_port(f, s):
199            p = urlparse(s.get('server', 'http://localhost'))
200            print >>f, 'port: remote:%s:%s:%s' % (p.port, p.hostname, p.port) 
201
202        def server_null(f,s): pass
203
204        def server_seer(f, s):
205            print >>f, 'seer: true'
206
207        server_service_out = {
208                'SMB': server_port,
209                'tmcd': server_port,
210                'userconfig': server_null,
211                'seer': server_seer,
212            }
[593e901]213        # XXX: end un hardcode this
214
215
216        seer_out = False
217        client_out = False
218        for e in [ e for e in topo.elements \
219                if isinstance(e, topdl.Computer) and e.get_attribute('portal')]:
220            myname = e.name[0]
221            type = e.get_attribute('portal_type')
[4e9719b]222            testbed = e.get_attribute('testbed')
[593e901]223
224            info = conninfo_to_dict(myname, connInfo)
225
226            if not info:
227                raise service_error(service_error.req,
228                        "No connectivity info for %s" % myname)
229
230            # Translate to physical name (ProtoGENI doesn't have DNS)
231            physname = nodes.get(myname, {'hostname': myname})['hostname']
232            peer = info.get('peer', "")
233            ldomain = parent.domain;
234
235            mexp = info.get('masterexperiment',"")
236            mproj, meid = mexp.split("/", 1)
237            mdomain = info.get('masterdomain',"")
238            muser = info.get('masteruser','root')
239            smbshare = info.get('smbshare', 'USERS')
240            ssh_port = info.get('ssh_port', '22')
241
242            active = info.get('active', 'False')
243
244            cfn = "%s/%s.gw.conf" % (tmpdir, myname.lower())
245            tunnelconfig = parent.attrs.has_key('TunnelCfg')
246            try:
247                f = open(cfn, "w")
248                if active == 'True':
249                    print >>f, "active: True"
250                    print >>f, "ssh_port: %s" % ssh_port
251                    if type in ('control', 'both'):
252                        for s in [s for s in services \
253                                if s.get('name', "") in parent.imports]:
[9b3627e]254                            server_service_out[s['name']](f, s)
[593e901]255
256                if tunnelconfig:
257                    print >>f, "tunnelip: %s" % tunnelconfig
258                print >>f, "peer: %s" % peer.lower()
259                print >>f, "ssh_pubkey: /usr/local/federation/etc/%s" % \
260                        pubkey_base
261                print >>f, "ssh_privkey: /usr/local/federation/etc/%s" % \
262                        secretkey_base
263                f.close()
[d3c8759]264            except EnvironmentError, e:
[593e901]265                raise service_error(service_error.internal,
266                        "Can't write protal config %s: %s" % (cfn, e))
267
268            if not client_out and type in ('control', 'both'):
269                try:
270                    f = open("%s/client.conf" % tmpdir, "w")
271                    print >>f, "ControlGateway: %s" % physname.lower()
272                    for s in services:
273                        if s.get('name',"") in parent.imports and \
274                                s.get('visibility','') == 'import':
275                            client_service_out[s['name']](f, s)
[9b3627e]276                    # Seer uses this to find credentials in the shared project
277                    # dir.
278                    print >>f, "ExperimentID: %s/%s" % (mproj, meid)
[4e9719b]279                    if testbed == master:
280                        print >>f, "SEERBase: True"
[593e901]281                    f.close()
[d3c8759]282                except EnvironmentError, e:
[593e901]283                    raise service_error(service_error.internal,
284                            "Cannot write client.conf: %s" %s)
285                client_out = True
286
287
[c119839]288
289    def export_store_info(self, cf, nodes, ssh_port, connInfo):
290        """
291        For the export requests in the connection info, install the peer names
292        at the experiment controller via SetValue calls.
293        """
294
295        for c in connInfo:
296            for p in [ p for p in c.get('parameter', []) \
297                    if p.get('type', '') == 'output']:
298
299                if p.get('name', '') == 'peer':
300                    k = p.get('key', None)
301                    surl = p.get('store', None)
302                    if surl and k and k.index('/') != -1:
303                        if self.debug:
304                            req = { 'name': k, 'value': 'debug' }
305                            self.call_SetValue(surl, req, cf)
306                        else:
307                            value = nodes.get(k[k.index('/')+1:], 
308                                    {}).get('hostname',"")
309                            if value:
310                                req = { 'name': k, 'value': value }
311                                self.call_SetValue(surl, req, cf)
312                            else:
313                                self.log.error("No hostname for %s" % \
314                                        k[k.index('/'):])
315                    else:
316                        self.log.error("Bad export request: %s" % p)
317                elif p.get('name', '') == 'ssh_port':
318                    k = p.get('key', None)
319                    surl = p.get('store', None)
320                    if surl and k:
[593e901]321                        req = { 'name': k, 'value': ssh_port }
[c119839]322                        self.call_SetValue(surl, req, cf)
323                    else:
324                        self.log.error("Bad export request: %s" % p)
325                else:
326
327                    self.log.error("Unknown export parameter: %s" % \
328                            p.get('name'))
329                    continue
330
331    def configure_nodes(self, topo, nodes, user, host, sshd, sshd_config,
[9b3627e]332            gate_cmd, node_cmd, pubkey, secretkey, federation_software, 
333            portal_software, stagingdir, tmpdir):
[c119839]334
[f8ae7aa]335        # These little functions/functors just make things more readable
336        class stage_file_type:
337            def __init__(self, user, host, stagingdir):
338                self.user = user
339                self.host = host
340                self.stagingdir = stagingdir
341                self.scp = "/usr/bin/scp -i .ssh/id_rsa -o " + \
342                        "'ForwardX11 no' -o 'StrictHostKeyChecking no' "
343
344            def __call__(self, script, file, dest="."):
345                # If the file is a full pathname, do not use stagingdir
346                if file.find('/') == -1:
347                    file = "%s/%s" % (self.stagingdir, file)
348                print >>script, "%s %s@%s:%s %s" % \
349                        (self.scp, self.user, self.host, file, dest)
350
351        def install_tar(script, loc, base):
352            tar = "/bin/tar"
353            mkdir="/bin/mkdir"
354
355            print >>script, "%s -p %s" % (mkdir, loc)
356            print >>script, "%s -C %s -xzf %s" % (tar, loc, base)
357
358        def install_rpm(script, base):
359            rpm = "/bin/rpm"
360            print >>script, "%s --install %s" % (rpm, base)
361
[c119839]362        fed_dir = "/usr/local/federation"
[f8ae7aa]363        fed_etc_dir = "%s/etc" % fed_dir
364        fed_bin_dir = "%s/bin" % fed_dir
365        fed_lib_dir = "%s/lib" % fed_dir
366
[c119839]367        ifconfig = "/sbin/ifconfig"
[f8ae7aa]368
369        stage_file = stage_file_type(user, host, stagingdir)
[c119839]370
371        for e in [ e for e in topo.elements if isinstance(e, topdl.Computer)]:
372            vname = e.name[0]
373            node = nodes.get(vname, {})
374            pname = node.get('hostname', None)
375            if pname:
376                script = open("%s/%s.startup" %(tmpdir, pname), "w")
377                # Reset the interfaces to the ones in the topo file
378                for i in [ i for i in e.interface \
379                        if not i.get_attribute('portal')]:
380                    pinf = node['interfaces'].get(i.name, None)
381                    addr = i.get_attribute('ip4_address') 
382                    netmask = i.get_attribute('ip4_netmask') or '255.255.255.0'
383                    if pinf and addr:
384                        print >>script, \
385                                "%s %s %s netmask %s"  % \
386                                (ifconfig, pinf, addr, netmask)
387                    else:
388                        self.log.error("Missing interface or address for %s" \
389                                % i.name)
390                   
[9b3627e]391                for l, f in federation_software:
392                    base = os.path.basename(f)
[f8ae7aa]393                    stage_file(script, base)
394                    if l: install_tar(script, l, base)
395                    else: install_rpm(script, base)
[9b3627e]396
[c119839]397                for s in e.software:
398                    s_base = s.location.rpartition('/')[2]
[f8ae7aa]399                    stage_file(script, s_base)
400                    if s.install: install_tar(script, s.install, s_base)
401                    else: install_rpm(script, s_base)
402
[8e6fe4d]403                for f in ('hosts', pubkey, secretkey, 'client.conf', 
[9b3627e]404                        'userconf'):
[f8ae7aa]405                    stage_file(script, f, fed_etc_dir)
[c119839]406                if sshd:
[f8ae7aa]407                    stage_file(script, sshd, fed_bin_dir)
[c119839]408                if sshd_config:
[f8ae7aa]409                    stage_file(script, sshd_config, fed_etc_dir)
410
[593e901]411                # Look in tmpdir to get the names.  They've all been copied
412                # into the (remote) staging dir
[c119839]413                if os.access("%s/%s.gw.conf" % (tmpdir, vname), os.R_OK):
[f8ae7aa]414                    stage_file(script, "%s.gw.conf" % vname, fed_etc_dir)
[c119839]415
[9b3627e]416                # Hackery dackery dock: the ProtoGENI python is really ancient.
[f8ae7aa]417                # A modern version (though packaged for Mandrake (remember
418                # Mandrake?  good times, good times)) should be in the
419                # federation_software list, but we need to move rename is for
420                # SEER.
[9b3627e]421                print >>script, "rm /usr/bin/python"
422                print >>script, "ln /usr/bin/python2.4 /usr/bin/python"
423                # Back to less hacky stuff
[8e6fe4d]424
[c119839]425                # Start commands
426                if e.get_attribute('portal') and gate_cmd:
[9b3627e]427                    # Install portal software
428                    for l, f in portal_software:
429                        base = os.path.basename(f)
[f8ae7aa]430                        stage_file(script, base)
431                        if l: install_tar(script, l, base)
432                        else: install_rpm(script, base)
[9b3627e]433
[c119839]434                    # Portals never have a user-specified start command
435                    print >>script, gate_cmd
436                elif node_cmd:
[8e6fe4d]437                    # XXX: debug
[f8ae7aa]438                    print >>script, "sudo perl -I%s %simport_key.pl /users/%s/.ssh/authorized_keys /root/.ssh/authorized_keys" % (fed_lib_dir, fed_bin_dir, user)
[8e6fe4d]439                    # XXX: debug
[c119839]440                    if e.get_attribute('startup'):
441                        print >>script, "%s \\$USER '%s'" % \
442                                (node_cmd, e.get_attribute('startup'))
443                    else:
444                        print >>script, node_cmd
445                script.close()
446                if not self.scp_file("%s/%s.startup" % (tmpdir, pname), 
447                        user, pname):
448                    self.log.error("Could not copy script to %s" % pname)
449            else:
450                self.log.error("Unmapped node: %s" % vname)
451
[0b799e0]452    def start_node(self, user, host, node):
453        # Place an identity on the node so that the copying can succeed
454        self.ssh_cmd(user, host, "scp .ssh/id_rsa %s:.ssh" % node)
455        self.ssh_cmd(user, node, "sudo /bin/sh ./%s.startup &" % node)
456
457    def start_nodes(self, user, host, nodes):
[c119839]458        threads = [ ]
459        for n in nodes:
[0b799e0]460            t = Thread(target=self.start_node, args=(user, host, n))
[c119839]461            t.start()
462            threads.append(t)
463
464        done = [not t.isAlive() for t in threads]
465        while not all(done):
466            self.log.info("Waiting for threads %s" % done)
467            time.sleep(10)
468            done = [not t.isAlive() for t in threads]
469
470
471
472
[593e901]473    def __call__(self, parent, aid, user, rspec, pubkey, secretkey, master,
474            ename, stagingdir, tmpdir, certfile, certpw, export_certfile, topo,
475            connInfo, services, timeout=0):
[c119839]476        """
477        Start a sub-experiment on a federant.
478
479        Get the current state, modify or create as appropriate, ship data
480        and configs and start the experiment.  There are small ordering
481        differences based on the initial state of the sub-experiment.
482        """
483
484        def random_slicename(user):
485            slicename = user
486            for i in range(0,5):
487                slicename += random.choice(string.ascii_letters)
488            return slicename
489
490        host = parent.staging_host
491        ctxt = fedd_ssl_context(my_cert=certfile, password=certpw)
492        # Local software dir
493        lsoftdir = "%s/software" % tmpdir
494
495        # Open up a temporary file to contain a script for setting up the
496        # filespace for the new experiment.
497        self.log.info("[start_segment]: creating script file")
498        try:
499            sf, scriptname = tempfile.mkstemp()
500            scriptfile = os.fdopen(sf, 'w')
[d3c8759]501        except EnvironmentError:
[c119839]502            return False
503
504        scriptbase = os.path.basename(scriptname)
505
506        # Script the filesystem changes
507        print >>scriptfile, "/bin/rm -rf %s" % stagingdir
508        print >>scriptfile, 'mkdir -p %s' % stagingdir
509        print >>scriptfile, "rm -f %s" % scriptbase
510        scriptfile.close()
511
512        # Move the script to the remote machine
513        # XXX: could collide tempfile names on the remote host
514        if self.scp_file(scriptname, user, host, scriptbase):
515            os.remove(scriptname)
516        else:
517            return False
518
519        # Execute the script (and the script's last line deletes it)
520        if not self.ssh_cmd(user, host, "sh -x %s" % scriptbase):
521            return False
522
523        try:
524            gcred = self.pg_call(self.sa_url, 'GetCredential', {}, ctxt)
525        except self.ProtoGENIError, e:
526            raise service_error(service_error.federant,
527                    "ProtoGENI: %s" % e)
528        # Find a slicename not in use
529        slicename = "fabereGpgL"
530        while True:
531            slicename = random_slicename(user)
532            try:
533                param = {
534                        'credential': gcred, 
535                        'hrn': slicename,
536                        'type': 'Slice'
537                        }
538                self.pg_call(self.sa_url, 'Resolve', param, ctxt)
539            except self.ProtoGENIError, e:
540                print e
541                break
542
543        self.log.info("Creating %s" % slicename)
544        f = open("./rspec", "w")
545        print >>f, "%s" % rspec
546        f.close()
547        # Create the slice and allocate resources.  If any of this stuff fails,
548        # the allocations will time out on PG in short order, so we just raise
549        # the service_error.
550        try:
551            param = {
552                    'credential': gcred, 
553                    'hrn': slicename,
554                    'type': 'Slice'
555                    }
556            slice_cred = self.pg_call(self.sa_url, 'Register', param, ctxt)
557            f = open("./slice_cred", "w")
558            print >>f, slice_cred
559            f.close()
560            # Populate the ssh keys (let PG format them)
561            param = {
562                    'credential': gcred, 
563                    }
564            keys =  self.pg_call(self.sa_url, 'GetKeys', param, ctxt)
565            # Grab and redeem a ticket
566            param = {
567                    'credential': slice_cred, 
568                    'rspec': rspec,
569                    }
570            ticket = self.pg_call(self.cm_url, 'GetTicket', param, ctxt)
571            f = open("./ticket", "w")
572            print >>f, ticket
573            f.close()
574            param = { 
575                    'credential': slice_cred, 
576                    'keys': keys,
577                    'ticket': ticket,
578                    }
579            sliver_cred, manifest = self.pg_call(self.cm_url, 
580                    'RedeemTicket', param, ctxt)
581            f = open("./sliver_cred", "w")
582            print >>f, sliver_cred
583            f.close()
584            f = open("./manifest", "w")
585            print >>f, manifest
586            f.close()
587            # start 'em up
588            param = { 
589                    'credential': sliver_cred,
590                    }
591            self.pg_call(self.cm_url, 'StartSliver', param, ctxt)
592        except self.ProtoGENIError, e:
593            raise service_error(service_error.federant,
[593e901]594                    "ProtoGENI: %s %s" % (e.code, e))
[c119839]595
596        # With manifest in hand, we can export the portal node names.
[9b3627e]597        nodes = self.manifest_to_dict(manifest)
[c119839]598        self.export_store_info(export_certfile, nodes, parent.ssh_port,
599                connInfo)
[593e901]600        self.generate_portal_configs(parent, topo, pubkey, secretkey, tmpdir, 
601                master, ename, connInfo, services, nodes)
602
603        # Copy software to the staging machine (done after generation to copy
604        # those, too)
605        for d in (tmpdir, lsoftdir):
606            if os.path.isdir(d):
607                for f in os.listdir(d):
608                    if not os.path.isdir("%s/%s" % (d, f)):
609                        if not self.scp_file("%s/%s" % (d, f), 
610                                user, host, "%s/%s" % (stagingdir, f)):
611                            self.log.error("Scp failed")
612                            return False
613
[c119839]614
615        # Now we wait for the nodes to start on PG
616        status = 'notready'
617        try:
618            while status == 'notready':
619                param = { 
620                        'credential': slice_cred
621                        }
622                r = self.pg_call(self.cm_url, 'SliceStatus', param, ctxt)
623                print r
624                status = r.get('status', 'notready')
625                if status == 'notready':
626                    time.sleep(30)
[593e901]627        except self.ProtoGENIError, e:
[c119839]628            raise service_error(service_error.federant,
[593e901]629                    "ProtoGENI: %s %s" % (e.code, e))
[c119839]630
631        if status == 'failed':
632            self.log.error('Sliver failed to start on ProtoGENI')
633            try:
634                param = { 
635                        'credential': slice_cred
636                        }
637                self.pg_call(self.cm_url, 'DeleteSliver', param, ctxt)
638            except self.ProtoGENIError, e:
639                raise service_error(service_error.federant,
640                    "ProtoGENI: %s" % e)
641            return False
642        else:
643            parent.state_lock.acquire()
[dd3e38b]644            parent.allocation[aid]['slice_name'] = slicename
[c119839]645            parent.allocation[aid]['slice_credential'] = slice_cred
646            parent.allocation[aid]['sliver_credential'] = sliver_cred
647            parent.allocation[aid]['manifest'] = manifest
648            parent.allocation[aid]['certfile'] = certfile
649            parent.allocation[aid]['certpw'] = certpw
650            parent.write_state()
651            parent.state_lock.release()
652
653        # The startcmds for portals and standard nodes (the Master Slave
654        # distinction is going away)
655        gate_cmd = parent.attrs.get('SlaveConnectorStartCmd', '/bin/true')
656        node_cmd = parent.attrs.get('SlaveNodeStartCmd', 'bin/true')
657
658        # Now we have configuration to do for ProtoGENI
659        self.configure_nodes(topo, nodes, user, parent.staging_host,
660                parent.sshd, parent.sshd_config, gate_cmd, node_cmd, 
[9b3627e]661                pubkey, secretkey, parent.federation_software, 
662                parent.portal_software, stagingdir, tmpdir)
[c119839]663
[0b799e0]664        self.start_nodes(user, parent.staging_host, 
665                [ n['hostname'] for n in nodes.values()])
[c119839]666
667        # Everything has gone OK.
668        return True
669
670class stop_segment(segment_base):
671    def __init__(self, log=None, keyfile=None, debug=False, 
672            ch_url=None, sa_url=None, cm_url=None):
673        segment_base.__init__(self, log=log, keyfile=keyfile, debug=debug,
674                ch_url=cm_url, sa_url=sa_url, cm_url=cm_url)
675
676    def __call__(self, parent, user, stagingdir, slice_cred, certfile, certpw):
677        """
678        Stop a sub experiment by calling swapexp on the federant
679        """
680        host = parent.staging_host
681        rv = False
682        try:
683            # Clean out tar files: we've gone over quota in the past
684            if stagingdir:
685                self.ssh_cmd(user, host, "rm -rf %s" % stagingdir)
686            if slice_cred:
687                self.log.error('Removing Sliver on ProtoGENI')
688                ctxt = fedd_ssl_context(my_cert=certfile, password=certpw)
689                try:
690                    param = { 
691                            'credential': slice_cred
692                            }
693                    self.pg_call(self.cm_url, 'DeleteSlice', param, ctxt)
694                except self.ProtoGENIError, e:
695                    raise service_error(service_error.federant,
696                        "ProtoGENI: %s" % e)
697            return True
698        except self.ssh_cmd_timeout:
699            rv = False
700        return rv
701
[dd3e38b]702class renew_segment(segment_base):
703    def __init__(self, log=None, debug=False, keyfile=None,
704            ch_url=None, sa_url=None, cm_url=None):
705        segment_base.__init__(self, log=log, keyfile=keyfile, debug=debug,
706                ch_url=cm_url, sa_url=sa_url, cm_url=cm_url)
707
708    def __call__(self, name, scred, interval, certfile, certpw):
709        ctxt = fedd_ssl_context(my_cert=certfile, password=certpw)
710        try:
711            expiration = time.strftime("%Y%m%dT%H:%M:%S",
712                    time.gmtime(time.time() + interval))
713            cred = self.pg_call(self.sa_url, 'GetCredential', {}, ctxt)
714
715            param = {
716                    'credential': scred,
717                    'expiration': expiration
718                    }
719            r = self.pg_call(self.sa_url, 'RenewSlice', param, ctxt)
720            param = {
721                    'credential': cred,
722                    'hrn': name,
723                    'type': 'Slice',
724                    }
725            slice = self.pg_call(self.sa_url, 'Resolve', param, ctxt)
726            uuid = slice.get('uuid', None)
727            if uuid == None:
728                sys.exit('No uuid for %s' % slicename)
729
730            print 'Calling GetCredential (uuid)'
731            param = {
732                    'credential': cred,
733                    'uuid': uuid,
734                    'type': 'Slice',
735                    }
736            new_scred = self.pg_call(self.sa_url, 'GetCredential', param, ctxt)
737            f = open('./new_slice_cred', 'w')
738            print >>f, new_scred
739            f.close()
740
741        except self.ProtoGENIError, e:
742            self.log.error("Failed to extend slice %s: %s" % (name, e))
743            return None
744        try:
745            print 'Calling RenewSlice (CM)'
746            param = {
747                    'credential': new_scred,
748                    }
749            r = self.pg_call(self.cm_url, 'RenewSlice', param, ctxt)
750        except self.ProtoGENIError, e:
751            self.log.warn("Failed to renew sliver for %s: %s" % (name, e))
752
753        return new_scred
754   
Note: See TracBrowser for help on using the repository browser.