source: fedd/federation/emulab_segment.py @ b709861

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

Rebooting works

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