source: fedd/federation/proxy_protogeni_segment.py @ 703859f

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

access is looking better, but segment is a screaming mess. I'm not sure that division makes any sense at all.

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