source: fedd/federation/proxy_protogeni_segment.py @ 9b3627e

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

SEER support

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