source: fedd/federation/proxy_protogeni_segment.py @ bc0b21b

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

Neaten things up a little and support rpms for federation and portal software in protoGENI

  • Property mode set to 100644
File size: 22.4 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            testbed = e.get_attribute('testbed')
219
220            info = conninfo_to_dict(myname, connInfo)
221
222            if not info:
223                raise service_error(service_error.req,
224                        "No connectivity info for %s" % myname)
225
226            # Translate to physical name (ProtoGENI doesn't have DNS)
227            physname = nodes.get(myname, {'hostname': myname})['hostname']
228            peer = info.get('peer', "")
229            ldomain = parent.domain;
230
231            mexp = info.get('masterexperiment',"")
232            mproj, meid = mexp.split("/", 1)
233            mdomain = info.get('masterdomain',"")
234            muser = info.get('masteruser','root')
235            smbshare = info.get('smbshare', 'USERS')
236            ssh_port = info.get('ssh_port', '22')
237
238            active = info.get('active', 'False')
239
240            cfn = "%s/%s.gw.conf" % (tmpdir, myname.lower())
241            tunnelconfig = parent.attrs.has_key('TunnelCfg')
242            try:
243                f = open(cfn, "w")
244                if active == 'True':
245                    print >>f, "active: True"
246                    print >>f, "ssh_port: %s" % ssh_port
247                    if type in ('control', 'both'):
248                        for s in [s for s in services \
249                                if s.get('name', "") in parent.imports]:
250                            server_service_out[s['name']](f, s)
251
252                if tunnelconfig:
253                    print >>f, "tunnelip: %s" % tunnelconfig
254                print >>f, "peer: %s" % peer.lower()
255                print >>f, "ssh_pubkey: /usr/local/federation/etc/%s" % \
256                        pubkey_base
257                print >>f, "ssh_privkey: /usr/local/federation/etc/%s" % \
258                        secretkey_base
259                f.close()
260            except IOError, e:
261                raise service_error(service_error.internal,
262                        "Can't write protal config %s: %s" % (cfn, e))
263
264            if not client_out and type in ('control', 'both'):
265                try:
266                    f = open("%s/client.conf" % tmpdir, "w")
267                    print >>f, "ControlGateway: %s" % physname.lower()
268                    for s in services:
269                        if s.get('name',"") in parent.imports and \
270                                s.get('visibility','') == 'import':
271                            client_service_out[s['name']](f, s)
272                    # Seer uses this to find credentials in the shared project
273                    # dir.
274                    print >>f, "ExperimentID: %s/%s" % (mproj, meid)
275                    if testbed == master:
276                        print >>f, "SEERBase: True"
277                    f.close()
278                except IOError, e:
279                    raise service_error(service_error.internal,
280                            "Cannot write client.conf: %s" %s)
281                client_out = True
282
283
284
285    def export_store_info(self, cf, nodes, ssh_port, connInfo):
286        """
287        For the export requests in the connection info, install the peer names
288        at the experiment controller via SetValue calls.
289        """
290
291        for c in connInfo:
292            for p in [ p for p in c.get('parameter', []) \
293                    if p.get('type', '') == 'output']:
294
295                if p.get('name', '') == 'peer':
296                    k = p.get('key', None)
297                    surl = p.get('store', None)
298                    if surl and k and k.index('/') != -1:
299                        if self.debug:
300                            req = { 'name': k, 'value': 'debug' }
301                            self.call_SetValue(surl, req, cf)
302                        else:
303                            value = nodes.get(k[k.index('/')+1:], 
304                                    {}).get('hostname',"")
305                            if value:
306                                req = { 'name': k, 'value': value }
307                                self.call_SetValue(surl, req, cf)
308                            else:
309                                self.log.error("No hostname for %s" % \
310                                        k[k.index('/'):])
311                    else:
312                        self.log.error("Bad export request: %s" % p)
313                elif p.get('name', '') == 'ssh_port':
314                    k = p.get('key', None)
315                    surl = p.get('store', None)
316                    if surl and k:
317                        req = { 'name': k, 'value': ssh_port }
318                        self.call_SetValue(surl, req, cf)
319                    else:
320                        self.log.error("Bad export request: %s" % p)
321                else:
322
323                    self.log.error("Unknown export parameter: %s" % \
324                            p.get('name'))
325                    continue
326
327    def configure_nodes(self, topo, nodes, user, host, sshd, sshd_config,
328            gate_cmd, node_cmd, pubkey, secretkey, federation_software, 
329            portal_software, stagingdir, tmpdir):
330
331        # These little functions/functors just make things more readable
332        class stage_file_type:
333            def __init__(self, user, host, stagingdir):
334                self.user = user
335                self.host = host
336                self.stagingdir = stagingdir
337                self.scp = "/usr/bin/scp -i .ssh/id_rsa -o " + \
338                        "'ForwardX11 no' -o 'StrictHostKeyChecking no' "
339
340            def __call__(self, script, file, dest="."):
341                # If the file is a full pathname, do not use stagingdir
342                if file.find('/') == -1:
343                    file = "%s/%s" % (self.stagingdir, file)
344                print >>script, "%s %s@%s:%s %s" % \
345                        (self.scp, self.user, self.host, file, dest)
346
347        def install_tar(script, loc, base):
348            tar = "/bin/tar"
349            mkdir="/bin/mkdir"
350
351            print >>script, "%s -p %s" % (mkdir, loc)
352            print >>script, "%s -C %s -xzf %s" % (tar, loc, base)
353
354        def install_rpm(script, base):
355            rpm = "/bin/rpm"
356            print >>script, "%s --install %s" % (rpm, base)
357
358        fed_dir = "/usr/local/federation"
359        fed_etc_dir = "%s/etc" % fed_dir
360        fed_bin_dir = "%s/bin" % fed_dir
361        fed_lib_dir = "%s/lib" % fed_dir
362
363        ifconfig = "/sbin/ifconfig"
364
365        stage_file = stage_file_type(user, host, stagingdir)
366
367        for e in [ e for e in topo.elements if isinstance(e, topdl.Computer)]:
368            vname = e.name[0]
369            node = nodes.get(vname, {})
370            pname = node.get('hostname', None)
371            if pname:
372                script = open("%s/%s.startup" %(tmpdir, pname), "w")
373                # Reset the interfaces to the ones in the topo file
374                for i in [ i for i in e.interface \
375                        if not i.get_attribute('portal')]:
376                    pinf = node['interfaces'].get(i.name, None)
377                    addr = i.get_attribute('ip4_address') 
378                    netmask = i.get_attribute('ip4_netmask') or '255.255.255.0'
379                    if pinf and addr:
380                        print >>script, \
381                                "%s %s %s netmask %s"  % \
382                                (ifconfig, pinf, addr, netmask)
383                    else:
384                        self.log.error("Missing interface or address for %s" \
385                                % i.name)
386                   
387                for l, f in federation_software:
388                    base = os.path.basename(f)
389                    stage_file(script, base)
390                    if l: install_tar(script, l, base)
391                    else: install_rpm(script, base)
392
393                for s in e.software:
394                    s_base = s.location.rpartition('/')[2]
395                    stage_file(script, s_base)
396                    if s.install: install_tar(script, s.install, s_base)
397                    else: install_rpm(script, s_base)
398
399                for f in ('hosts', pubkey, secretkey, 'client.conf', 
400                        'userconf'):
401                    stage_file(script, f, fed_etc_dir)
402                if sshd:
403                    stage_file(script, sshd, fed_bin_dir)
404                if sshd_config:
405                    stage_file(script, sshd_config, fed_etc_dir)
406
407                # Look in tmpdir to get the names.  They've all been copied
408                # into the (remote) staging dir
409                if os.access("%s/%s.gw.conf" % (tmpdir, vname), os.R_OK):
410                    stage_file(script, "%s.gw.conf" % vname, fed_etc_dir)
411
412                # Hackery dackery dock: the ProtoGENI python is really ancient.
413                # A modern version (though packaged for Mandrake (remember
414                # Mandrake?  good times, good times)) should be in the
415                # federation_software list, but we need to move rename is for
416                # SEER.
417                print >>script, "rm /usr/bin/python"
418                print >>script, "ln /usr/bin/python2.4 /usr/bin/python"
419                # Back to less hacky stuff
420
421                # Start commands
422                if e.get_attribute('portal') and gate_cmd:
423                    # Install portal software
424                    for l, f in portal_software:
425                        base = os.path.basename(f)
426                        stage_file(script, base)
427                        if l: install_tar(script, l, base)
428                        else: install_rpm(script, base)
429
430                    # Portals never have a user-specified start command
431                    print >>script, gate_cmd
432                elif node_cmd:
433                    # XXX: debug
434                    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)
435                    # XXX: debug
436                    if e.get_attribute('startup'):
437                        print >>script, "%s \\$USER '%s'" % \
438                                (node_cmd, e.get_attribute('startup'))
439                    else:
440                        print >>script, node_cmd
441                script.close()
442                if not self.scp_file("%s/%s.startup" % (tmpdir, pname), 
443                        user, pname):
444                    self.log.error("Could not copy script to %s" % pname)
445            else:
446                self.log.error("Unmapped node: %s" % vname)
447
448    def start_node(self, user, host, node):
449        # Place an identity on the node so that the copying can succeed
450        self.ssh_cmd(user, host, "scp .ssh/id_rsa %s:.ssh" % node)
451        self.ssh_cmd(user, node, "sudo /bin/sh ./%s.startup &" % node)
452
453    def start_nodes(self, user, host, nodes):
454        threads = [ ]
455        for n in nodes:
456            t = Thread(target=self.start_node, args=(user, host, n))
457            t.start()
458            threads.append(t)
459
460        done = [not t.isAlive() for t in threads]
461        while not all(done):
462            self.log.info("Waiting for threads %s" % done)
463            time.sleep(10)
464            done = [not t.isAlive() for t in threads]
465
466
467
468
469    def __call__(self, parent, aid, user, rspec, pubkey, secretkey, master,
470            ename, stagingdir, tmpdir, certfile, certpw, export_certfile, topo,
471            connInfo, services, timeout=0):
472        """
473        Start a sub-experiment on a federant.
474
475        Get the current state, modify or create as appropriate, ship data
476        and configs and start the experiment.  There are small ordering
477        differences based on the initial state of the sub-experiment.
478        """
479
480        def random_slicename(user):
481            slicename = user
482            for i in range(0,5):
483                slicename += random.choice(string.ascii_letters)
484            return slicename
485
486        host = parent.staging_host
487        ctxt = fedd_ssl_context(my_cert=certfile, password=certpw)
488        # Local software dir
489        lsoftdir = "%s/software" % tmpdir
490
491        # Open up a temporary file to contain a script for setting up the
492        # filespace for the new experiment.
493        self.log.info("[start_segment]: creating script file")
494        try:
495            sf, scriptname = tempfile.mkstemp()
496            scriptfile = os.fdopen(sf, 'w')
497        except IOError:
498            return False
499
500        scriptbase = os.path.basename(scriptname)
501
502        # Script the filesystem changes
503        print >>scriptfile, "/bin/rm -rf %s" % stagingdir
504        print >>scriptfile, 'mkdir -p %s' % stagingdir
505        print >>scriptfile, "rm -f %s" % scriptbase
506        scriptfile.close()
507
508        # Move the script to the remote machine
509        # XXX: could collide tempfile names on the remote host
510        if self.scp_file(scriptname, user, host, scriptbase):
511            os.remove(scriptname)
512        else:
513            return False
514
515        # Execute the script (and the script's last line deletes it)
516        if not self.ssh_cmd(user, host, "sh -x %s" % scriptbase):
517            return False
518
519        try:
520            gcred = self.pg_call(self.sa_url, 'GetCredential', {}, ctxt)
521        except self.ProtoGENIError, e:
522            raise service_error(service_error.federant,
523                    "ProtoGENI: %s" % e)
524        # Find a slicename not in use
525        slicename = "fabereGpgL"
526        while True:
527            slicename = random_slicename(user)
528            try:
529                param = {
530                        'credential': gcred, 
531                        'hrn': slicename,
532                        'type': 'Slice'
533                        }
534                self.pg_call(self.sa_url, 'Resolve', param, ctxt)
535            except self.ProtoGENIError, e:
536                print e
537                break
538
539        self.log.info("Creating %s" % slicename)
540        f = open("./rspec", "w")
541        print >>f, "%s" % rspec
542        f.close()
543        # Create the slice and allocate resources.  If any of this stuff fails,
544        # the allocations will time out on PG in short order, so we just raise
545        # the service_error.
546        try:
547            param = {
548                    'credential': gcred, 
549                    'hrn': slicename,
550                    'type': 'Slice'
551                    }
552            slice_cred = self.pg_call(self.sa_url, 'Register', param, ctxt)
553            f = open("./slice_cred", "w")
554            print >>f, slice_cred
555            f.close()
556            # Populate the ssh keys (let PG format them)
557            param = {
558                    'credential': gcred, 
559                    }
560            keys =  self.pg_call(self.sa_url, 'GetKeys', param, ctxt)
561            # Grab and redeem a ticket
562            param = {
563                    'credential': slice_cred, 
564                    'rspec': rspec,
565                    }
566            ticket = self.pg_call(self.cm_url, 'GetTicket', param, ctxt)
567            f = open("./ticket", "w")
568            print >>f, ticket
569            f.close()
570            param = { 
571                    'credential': slice_cred, 
572                    'keys': keys,
573                    'ticket': ticket,
574                    }
575            sliver_cred, manifest = self.pg_call(self.cm_url, 
576                    'RedeemTicket', param, ctxt)
577            f = open("./sliver_cred", "w")
578            print >>f, sliver_cred
579            f.close()
580            f = open("./manifest", "w")
581            print >>f, manifest
582            f.close()
583            # start 'em up
584            param = { 
585                    'credential': sliver_cred,
586                    }
587            self.pg_call(self.cm_url, 'StartSliver', param, ctxt)
588        except self.ProtoGENIError, e:
589            raise service_error(service_error.federant,
590                    "ProtoGENI: %s %s" % (e.code, e))
591
592        # With manifest in hand, we can export the portal node names.
593        nodes = self.manifest_to_dict(manifest)
594        self.export_store_info(export_certfile, nodes, parent.ssh_port,
595                connInfo)
596        self.generate_portal_configs(parent, topo, pubkey, secretkey, tmpdir, 
597                master, ename, connInfo, services, nodes)
598
599        # Copy software to the staging machine (done after generation to copy
600        # those, too)
601        for d in (tmpdir, lsoftdir):
602            if os.path.isdir(d):
603                for f in os.listdir(d):
604                    if not os.path.isdir("%s/%s" % (d, f)):
605                        if not self.scp_file("%s/%s" % (d, f), 
606                                user, host, "%s/%s" % (stagingdir, f)):
607                            self.log.error("Scp failed")
608                            return False
609
610
611        # Now we wait for the nodes to start on PG
612        status = 'notready'
613        try:
614            while status == 'notready':
615                param = { 
616                        'credential': slice_cred
617                        }
618                r = self.pg_call(self.cm_url, 'SliceStatus', param, ctxt)
619                print r
620                status = r.get('status', 'notready')
621                if status == 'notready':
622                    time.sleep(30)
623        except self.ProtoGENIError, e:
624            raise service_error(service_error.federant,
625                    "ProtoGENI: %s %s" % (e.code, e))
626
627        if status == 'failed':
628            self.log.error('Sliver failed to start on ProtoGENI')
629            try:
630                param = { 
631                        'credential': slice_cred
632                        }
633                self.pg_call(self.cm_url, 'DeleteSliver', param, ctxt)
634            except self.ProtoGENIError, e:
635                raise service_error(service_error.federant,
636                    "ProtoGENI: %s" % e)
637            return False
638        else:
639            parent.state_lock.acquire()
640            parent.allocation[aid]['slice_name'] = slicename
641            parent.allocation[aid]['slice_credential'] = slice_cred
642            parent.allocation[aid]['sliver_credential'] = sliver_cred
643            parent.allocation[aid]['manifest'] = manifest
644            parent.allocation[aid]['certfile'] = certfile
645            parent.allocation[aid]['certpw'] = certpw
646            parent.write_state()
647            parent.state_lock.release()
648
649        # The startcmds for portals and standard nodes (the Master Slave
650        # distinction is going away)
651        gate_cmd = parent.attrs.get('SlaveConnectorStartCmd', '/bin/true')
652        node_cmd = parent.attrs.get('SlaveNodeStartCmd', 'bin/true')
653
654        # Now we have configuration to do for ProtoGENI
655        self.configure_nodes(topo, nodes, user, parent.staging_host,
656                parent.sshd, parent.sshd_config, gate_cmd, node_cmd, 
657                pubkey, secretkey, parent.federation_software, 
658                parent.portal_software, stagingdir, tmpdir)
659
660        self.start_nodes(user, parent.staging_host, 
661                [ n['hostname'] for n in nodes.values()])
662
663        # Everything has gone OK.
664        return True
665
666class stop_segment(segment_base):
667    def __init__(self, log=None, keyfile=None, debug=False, 
668            ch_url=None, sa_url=None, cm_url=None):
669        segment_base.__init__(self, log=log, keyfile=keyfile, debug=debug,
670                ch_url=cm_url, sa_url=sa_url, cm_url=cm_url)
671
672    def __call__(self, parent, user, stagingdir, slice_cred, certfile, certpw):
673        """
674        Stop a sub experiment by calling swapexp on the federant
675        """
676        host = parent.staging_host
677        rv = False
678        try:
679            # Clean out tar files: we've gone over quota in the past
680            if stagingdir:
681                self.ssh_cmd(user, host, "rm -rf %s" % stagingdir)
682            if slice_cred:
683                self.log.error('Removing Sliver on ProtoGENI')
684                ctxt = fedd_ssl_context(my_cert=certfile, password=certpw)
685                try:
686                    param = { 
687                            'credential': slice_cred
688                            }
689                    self.pg_call(self.cm_url, 'DeleteSlice', param, ctxt)
690                except self.ProtoGENIError, e:
691                    raise service_error(service_error.federant,
692                        "ProtoGENI: %s" % e)
693            return True
694        except self.ssh_cmd_timeout:
695            rv = False
696        return rv
697
698class renew_segment(segment_base):
699    def __init__(self, log=None, debug=False, keyfile=None,
700            ch_url=None, sa_url=None, cm_url=None):
701        segment_base.__init__(self, log=log, keyfile=keyfile, debug=debug,
702                ch_url=cm_url, sa_url=sa_url, cm_url=cm_url)
703
704    def __call__(self, name, scred, interval, certfile, certpw):
705        ctxt = fedd_ssl_context(my_cert=certfile, password=certpw)
706        try:
707            expiration = time.strftime("%Y%m%dT%H:%M:%S",
708                    time.gmtime(time.time() + interval))
709            cred = self.pg_call(self.sa_url, 'GetCredential', {}, ctxt)
710
711            param = {
712                    'credential': scred,
713                    'expiration': expiration
714                    }
715            r = self.pg_call(self.sa_url, 'RenewSlice', param, ctxt)
716            param = {
717                    'credential': cred,
718                    'hrn': name,
719                    'type': 'Slice',
720                    }
721            slice = self.pg_call(self.sa_url, 'Resolve', param, ctxt)
722            uuid = slice.get('uuid', None)
723            if uuid == None:
724                sys.exit('No uuid for %s' % slicename)
725
726            print 'Calling GetCredential (uuid)'
727            param = {
728                    'credential': cred,
729                    'uuid': uuid,
730                    'type': 'Slice',
731                    }
732            new_scred = self.pg_call(self.sa_url, 'GetCredential', param, ctxt)
733            f = open('./new_slice_cred', 'w')
734            print >>f, new_scred
735            f.close()
736
737        except self.ProtoGENIError, e:
738            self.log.error("Failed to extend slice %s: %s" % (name, e))
739            return None
740        try:
741            print 'Calling RenewSlice (CM)'
742            param = {
743                    'credential': new_scred,
744                    }
745            r = self.pg_call(self.cm_url, 'RenewSlice', param, ctxt)
746        except self.ProtoGENIError, e:
747            self.log.warn("Failed to renew sliver for %s: %s" % (name, e))
748
749        return new_scred
750   
Note: See TracBrowser for help on using the repository browser.