source: fedd/federation/emulab_segment.py @ 1ae1aa2

compt_changesinfo-ops
Last change on this file since 1ae1aa2 was 1ae1aa2, checked in by Ted Faber <faber@…>, 13 years ago

Reload interface works

  • Property mode set to 100644
File size: 9.3 KB
Line 
1#!/usr/local/bin/python
2
3import logging 
4import util
5import topdl
6
7from M2Crypto import SSL
8from M2Crypto.m2xmlrpclib import SSL_Transport
9from xmlrpclib import ServerProxy, dumps, loads, Fault, Error, Binary
10from M2Crypto.SSL import SSLError
11from M2Crypto.BIO import BIOError
12from socket import error as socket_error
13from socket import sslerror
14import httplib
15from federation.util import fedd_ssl_context
16from federation import service_error
17from federation.operation_status import operation_status
18
19class emulab_segment:
20    class node_info:
21        def __init__(self, name, pname, status=None, osname=None, 
22                osversion=None, image=None):
23            self.name = name
24            self.pname = pname
25            self.status = status
26            self.osname = osname
27            self.osversion = osversion
28            self.image = image
29        def getOS(self):
30            rv = None
31            if self.osname or self.osversion:
32                rv = topdl.OperatingSystem(name=self.osname, 
33                        version=self.osversion)
34            if self.image and rv:
35                rv.set_attribute('image', self.image)
36            return rv
37
38    def __init__(self, boss, cert):
39        self.ctxt = fedd_ssl_context(my_cert=cert)
40        self.ctxt.set_verify(SSL.verify_none, 10)
41        self.boss = boss
42        self.null = """
43set ns [new Simulator]
44source tb_compat.tcl
45
46set a [$ns node]
47
48$ns rtproto Session
49$ns run
50"""
51        self.log =  getattr(self, 'log', None) 
52        self.debug = getattr(self, 'debug', False)
53        self.node = { }
54        self.status = [ ]
55        self.node_info = emulab_segment.node_info
56
57    def emulab_call(self, method, params):
58        VERSION = 0.1
59        try:
60            transport = SSL_Transport(self.ctxt)
61            port = ServerProxy(self.boss, transport=transport)
62            remote_method = getattr(port, method, None)
63            if remote_method is not None:
64                resp = remote_method(VERSION, params)
65            else:
66                raise service_error(service_error.internal, 
67                        "Bad method: %s" % method)
68        except socket_error, e:
69            raise service_error(service_error.connect, 
70                    "Cannot connect" % e)
71            raise e
72        except BIOError, e:
73            if self.log:
74                self.log.warn("BIO error: %s" % e)
75            raise e
76        except sslerror, e:
77            if self.log:
78                self.log.warn("SSL (socket) error: %s" %  e)
79            raise e
80        except SSLError, e:
81            if self.log:
82                self.log.warn("SSL error: %s" % e)
83            raise e
84        except httplib.HTTPException, e:
85            if self.log:
86                self.log.warn("HTTP error: %s" % e)
87            raise e
88        except Fault, f:
89            raise service_error(service_error.protocol, 
90                    "Remote XMLRPC Fault: %s" % f)
91        except Error, e:
92            raise service_error(service_error.protocol, 
93                    "Remote XMLRPC Fault: %s" % e)
94
95        code = resp.get('code', -1)
96        if code ==0:
97            return (code, resp.get('value', None))
98        else:
99            return (code, resp.get('output', None))
100
101    def get_state(self, pid, eid):
102        """
103        Return the state of the experiment as reported by emulab
104        """
105
106        if self.debug:
107            state = 'swapped'
108        else:
109            params =  { 'proj': pid, 'exp': eid }
110            code, state = self.emulab_call('experiment.state', params)
111            if code != 0:
112                state = 'none'
113
114        if self.log:
115            self.log.debug("State is %s" % state)
116        return state
117
118    def make_null_experiment(self, pid, eid, tmpdir, gid=None):
119        """
120        Create a null copy of the experiment so that we capture any logs there
121        if the modify fails.  Emulab software discards the logs from a failed
122        startexp.
123        """
124
125        if self.debug:
126            if self.log:
127                self.log.debug("[make_null_experiment]: " + \
128                        "(debug) Creating experiment")
129            return True
130        else:
131            params = {
132                    'proj': pid,
133                    'exp': eid, 
134                    'nsfilestr': self.null,
135                    'batch': False,
136                    'idleswap': 0,
137                    'noidleswap_reason': 'Federated experiment',
138                    'noswapin': True,
139                    'wait': True
140                    }
141            if gid is not None:
142                params['group'] = gid
143            if self.log:
144                self.log.info("[make_null_experiment]: Creating experiment")
145            code, value = self.emulab_call('experiment.startexp', params)
146
147            if self.log:
148                if code == 0: 
149                    self.log.info('[make_null_experiment]: Create succeeded')
150                else: 
151                    self.log.error('[make_null_experiment]: Create failed: %s' \
152                            % value)
153
154            return code == 0
155
156    def swap_exp(self, pid, eid, direction='out', wait=True):
157        """
158        Swap experiment in.
159        """
160        if self.debug:
161            if self.log:
162                self.log.info("[swap_exp]: (debug) Swapping %s %s" % \
163                        (eid, direction))
164            return True
165        else:
166            if self.log:
167                self.log.info("[swap_exp]: Swapping %s %s" % (eid, direction))
168            params = {
169                    'proj': pid,
170                    'exp': eid,
171                    'direction': direction,
172                    'wait': wait,
173                    }
174            code, value = self.emulab_call('experiment.swapexp', params)
175
176            if self.log:
177                if code == 0: self.log.info('[swap_exp]: Swap succeeded')
178                else: self.log.error('[swap_exp]: Swap failed: %s' % value)
179
180        return code == 0
181
182    def terminate_exp(self, pid, eid, wait=True):
183        """
184        Completely terminate experiment
185        """
186        if self.debug:
187            if self.log:
188                self.log.info("[swap_exp]: (debug) terminate %s" %  eid)
189            return True
190        else:
191            if self.log:
192                self.log.info("[swap_exp]: Terminating %s" % eid)
193            params = {
194                    'proj': pid,
195                    'exp': eid,
196                    'wait': wait,
197                    }
198            code, value = self.emulab_call('experiment.endexp', params)
199
200            if self.log:
201                if code == 0: self.log.info('[swap_exp]: Terminate succeeded')
202                else: self.log.error('[swap_exp]: Terminate failed: %s' % value)
203
204        return code == 0
205
206    def modify_exp(self, pid, eid, tcl, wait=True):
207        if self.debug:
208            self.log.info("[modify_exp]: (debug) Modifying %s" % eid)
209            return True
210        else:
211            self.log.info("[modify_exp]: Modifying %s" % eid)
212            params = {
213                    'proj': pid,
214                    'exp': eid,
215                    'nsfilestr': tcl,
216                    'wait': wait,
217                    'reboot': True,
218                    'restart_eventsys': True,
219                    }
220            code, value = self.emulab_call('experiment.modify', params)
221            if self.log:
222                if code == 0: 
223                    self.log.info('[modify_exp]: Modify succeeded')
224                else: 
225                    self.log.error('[modify_exp]: Modify failed: %s' \
226                            % value)
227            return code == 0
228
229    def get_osid_map(self):
230        oses = { }
231        code, osids = self.emulab_call('osid.getlist', {})
232        for key, val in osids.items():
233            val['imageid'] = key
234            oses[val['osid']] = val
235        return oses
236
237    def get_mapping(self, pid, eid):
238        """
239        Get the physical to virtual mapping from the expinfo command and save
240        it in the self.map member.
241        """
242
243        ev_ok = ('ISUP', 'ALWAYSUP' )
244
245        if self.debug:
246            if self.log:
247                self.log.info("[get_mapping] (debug) Generating mapping")
248                return True
249        else:
250            if self.log:
251                self.log.info("[get_mapping] Generating mapping")
252
253            osidmap = self.get_osid_map()
254
255            params = {
256                    'proj': pid,
257                    'exp': eid,
258                    'aspect': 'mapping'
259                    }
260            code, nodes = self.emulab_call('experiment.info', params)
261            if code ==0:
262                for k, v in nodes.items():
263                    if v.get('erole', False) and 'pnode' in v:
264                        st = v.get('status', 'up')
265                        ev = v.get('eventstatus', 'ISUP')
266                        os = v.get('osid', None)
267
268                        if st == 'up' and ev in ev_ok: st = 'active'
269                        else: st = 'failed'
270
271                        if os and os in osidmap:
272                           osname = osidmap[os].get('OS', None)
273                           osversion = osidmap[os].get('version', None)
274                           osimage = "%s/%s" % \
275                                   ( osidmap[os].get('pid', ''), 
276                                           osidmap[os].get('imageid', ''))
277                        else:
278                            osname = osversion = osimage = None
279
280                        self.node[k] = self.node_info(k, v['pnode'], st,
281                                osname, osversion, osimage)
282                if self.log:
283                    self.log.info("Mapping complete")
284                return True
285            else:
286                raise service_error(service_error.internal,
287                        "Cannot get node mapping of segment:%s/%s" % (pid, eid))
288    def get_image(self, node, top):
289        for e in top.elements:
290            if isinstance(e, topdl.Computer):
291                if node == e.name:
292                    if e.os: 
293                        return e.os[0].get_attribute('image')
294        return None
295
296
297    def do_operation(self, op, lnode, pnode, params, top):
298        """
299        Carry out operation on node in the given experiment.
300        """
301        def get_param(params, name):
302            if params is None:
303                return None
304            for d in params:
305                if 'attribute' in d and d['attribute'] == name:
306                    return d.get('value', None)
307            else:
308                return None
309
310        op = op.lower()
311
312        if op == 'restore':
313            state = get_param(params, 'state')
314            if state is None:
315                self.status.append(operation_status(lnode, 
316                        operation_status.bad_param, 'No state to restore'))
317                return False
318            elif state == 'initial': 
319                image = self.get_image(lnode, top)
320                if image:
321                    pid, iid = image.split('/')
322                    p = {'nodes': pnode, 'imagename': iid, 'imageproj': pid, 
323                            'wait': False}
324                    code, result = self.emulab_call('node.reload', p)
325                    if code == 0: 
326                        self.status.append(operation_status(lnode,
327                            operation_status.success, 'reloading'))
328                        return True
329                    else:
330                        self.status.append(operation_status(lnode,
331                                operation_status.federant, 
332                                'Error code: %d' % code))
333                        return False
334                else:
335                    self.status.append(operation_status(lnode,
336                            operation_status.federant, 
337                            'cannot find imageid??'))
338                    return False
339            elif state == 'boot': 
340                p = {'nodes': pnode, 'wait': False}
341                code, result = self.emulab_call('node.reboot', p)
342                if code == 0: 
343                    self.status.append(operation_status(lnode,
344                        operation_status.success, 'rebooting'))
345                    return True
346                else:
347                    self.status.append(operation_status(lnode,
348                            operation_status.federant, 'Error code: %d' % code))
349                    return False
350            else: 
351                self.status.append(operation_status(lnode, 
352                        operation_status.bad_param, 
353                        "Unsupported state %s" % state))
354                return False
355        else: 
356            self.status.append(operation_status(lnode, operation_status.unsupp))
357            return False
358
Note: See TracBrowser for help on using the repository browser.