4
4
import operator
5
5
import os
6
6
import pty
7
- import re
8
7
import select
9
- import time
8
+ from subprocess import PIPE , STDOUT
10
9
11
10
# pylint: disable=import-error
12
11
from mininet .log import error , debug
13
12
from mininet .node import Host
14
- from subprocess import PIPE , STDOUT
15
13
16
14
from mininet_test_util import DEVNULL
17
15
18
16
def MakeDockerHost (image , prefix = 'mininet' , startup_timeout_ms = None ):
17
+
19
18
class ImageHost (DockerHost ):
20
- def __init__ ( self , * args , ** kwargs ):
19
+
20
+ def __init__ (self , * args , ** kwargs ):
21
21
host_name = args [0 ]
22
22
kwargs ['image' ] = image
23
23
assert kwargs ['tmpdir' ], 'tmpdir required for docker host'
@@ -29,7 +29,7 @@ def __init__( self, *args, **kwargs ):
29
29
env_val = os .environ ['DOCKER_STARTUP_TIMEOUT_MS' ]
30
30
if env_val :
31
31
kwargs ['startup_timeout_ms' ] = int (env_val )
32
- DockerHost .__init__ (self , * args , ** kwargs )
32
+ DockerHost .__init__ (self , * args , ** kwargs )
33
33
return ImageHost
34
34
35
35
@@ -59,22 +59,24 @@ class DockerHost(Host):
59
59
vol_maps = None
60
60
prefix = None
61
61
startup_timeout_ms = None
62
-
62
+ container = None
63
+ pollIn = None
64
+ active_log = None
63
65
64
66
def __init__ (self , name , image = None , tmpdir = None , prefix = None , env_vars = [],
65
- vol_maps = [], startup_timeout_ms = STARTUP_TIMEOUT_MS , ** kwargs ):
67
+ vol_maps = [], startup_timeout_ms = STARTUP_TIMEOUT_MS , ** kwargs ):
66
68
self .image = image
67
69
self .tmpdir = tmpdir
68
70
self .prefix = prefix
69
71
self .env_vars = env_vars
70
72
self .vol_maps = vol_maps
71
73
self .startup_timeout_ms = startup_timeout_ms
72
- Host .__init__ ( self , name , ** kwargs )
74
+ Host .__init__ (self , name , ** kwargs )
73
75
74
- def startShell ( self ):
75
- "Start a shell process for running commands"
76
+ def startShell (self ):
77
+ """ Start a shell process for running commands."" "
76
78
if self .shell :
77
- error ( "%s: shell is already running" )
79
+ error (' shell is already running' )
78
80
return
79
81
80
82
self .container = '%s-%s' % (self .prefix , self .name )
@@ -86,12 +88,13 @@ def startShell( self ):
86
88
container_tmp_dir = os .path .join (os .path .abspath (self .tmpdir ), 'tmp' )
87
89
tmp_volume = container_tmp_dir + ':/tmp'
88
90
89
- base_cmd = [ "docker" , "run" , "-ti" , "--privileged" , "--entrypoint" , "env" ,
90
- "--net=none" , "-h" , self .name , "--name" , self .container ]
91
- env_args = reduce (operator .add , ([ '--env' , var ] for var in self .env_vars ), [])
92
- vol_args = reduce (operator .add , ([ '-v' , var ] for var in self .vol_maps ), [ '-v' , tmp_volume ])
93
- image_args = [ self .image , "TERM=dumb" , "PS1=" + chr (127 ), "bash" , "--norc" ,
94
- "-is" , "mininet:" + self .name ]
91
+ base_cmd = ["docker" , "run" , "-ti" , "--privileged" , "--entrypoint" , "env" ,
92
+ "--net=none" , "-h" , self .name , "--name" , self .container ]
93
+ env_args = reduce (operator .add , (['--env' , var ] for var in self .env_vars ), [])
94
+ vol_args = reduce (operator .add , (['-v' , var ] for var in self .vol_maps ), ['-v' , tmp_volume ])
95
+ image_args = [
96
+ self .image , "TERM=dumb" , "PS1=" + chr (127 ), "bash" , "--norc" ,
97
+ "-is" , "mininet:" + self .name ]
95
98
cmd = base_cmd + env_args + vol_args + image_args
96
99
self .master , self .slave = pty .openpty ()
97
100
debug ('docker command "%s", fd %d, fd %d' % (' ' .join (cmd ), self .master , self .slave ))
@@ -130,11 +133,11 @@ def startShell( self ):
130
133
def kill (self , purge = False ):
131
134
debug ('killing container %s.' % self .container )
132
135
if purge :
133
- kill_cmd = [ "docker" , "rm" , "-f" , self .container ]
136
+ kill_cmd = ["docker" , "rm" , "-f" , self .container ]
134
137
else :
135
- kill_cmd = [ "docker" , "kill" , self .container ]
138
+ kill_cmd = ["docker" , "kill" , self .container ]
136
139
try :
137
- kill_pipe = self ._popen ( kill_cmd , stdin = DEVNULL , stdout = PIPE , stderr = STDOUT )
140
+ kill_pipe = self ._popen (kill_cmd , stdin = DEVNULL , stdout = PIPE , stderr = STDOUT )
138
141
kill_pipe .stdout .readlines ()
139
142
kill_pipe .stdout .close ()
140
143
except :
@@ -144,8 +147,8 @@ def kill(self, purge=False):
144
147
145
148
def inspect_pid (self ):
146
149
try :
147
- pid_cmd = ["docker" ,"inspect" ,"--format={{ .State.Pid }}" , self .container ]
148
- pid_pipe = self ._popen ( pid_cmd , stdin = DEVNULL , stdout = PIPE , stderr = STDOUT )
150
+ pid_cmd = ["docker" , "inspect" , "--format={{ .State.Pid }}" , self .container ]
151
+ pid_pipe = self ._popen (pid_cmd , stdin = DEVNULL , stdout = PIPE , stderr = STDOUT )
149
152
ps_out = pid_pipe .stdout .readlines ()
150
153
pid_pipe .stdout .close ()
151
154
return int (ps_out [0 ])
@@ -200,37 +203,39 @@ def wait(self):
200
203
self .active_pipe .returncode = self .active_pipe .wait ()
201
204
self .terminate ()
202
205
return self .active_pipe_returncode
203
- except Exception as e :
204
- error ('Exception waiting for %s: %s' % (self .container , e ))
206
+ except Exception as err :
207
+ error ('Exception waiting for %s: %s' % (self .container , err ))
205
208
self .terminate ()
206
209
raise
207
210
208
- def read ( self , maxbytes = 1024 ):
211
+ def read (self , maxbytes = 1024 ):
209
212
poll_results = self .pollIn .poll (self .startup_timeout_ms )
210
213
data_ready = poll_results and (poll_results [0 ][1 ] & select .POLLIN )
211
- assert data_ready , ('Timeout waiting for read data on %d after %ds' %
212
- (self .stdout .fileno (), self .startup_timeout_ms / 1000 ))
214
+ assert data_ready , (
215
+ 'Timeout waiting for read data on %d after %ds' %
216
+ (self .stdout .fileno (), self .startup_timeout_ms / 1e3 ))
213
217
return Host .read (self , maxbytes )
214
218
215
219
def terminate (self ):
216
220
"""Override Mininet terminate() to partially avoid pty leak."""
217
- debug ('Terminating container %s, shell %s, pipe %s' % (self .container , self .shell , self .active_pipe ))
221
+ debug ('Terminating container %s, shell %s, pipe %s' % (
222
+ self .container , self .shell , self .active_pipe ))
218
223
if self .slave :
219
224
os .close (self .slave )
220
225
self .slave = None
221
226
if self .shell is not None :
222
227
self .stdin .close ()
223
228
self .stdin = None
224
229
self .master = None
225
- if self .shell .returncode == None :
230
+ if self .shell .returncode is None :
226
231
self .shell .kill ()
227
232
self .shell .poll ()
228
233
self .kill ()
229
234
self .shell = None
230
235
if self .active_pipe :
231
236
if self .active_pipe .stdout :
232
237
self .active_pipe .stdout .close ()
233
- if self .active_pipe .returncode == None :
238
+ if self .active_pipe .returncode is None :
234
239
self .active_pipe .kill ()
235
240
self .active_pipe .poll ()
236
241
self .active_pipe_returncode = self .active_pipe .returncode
@@ -241,15 +246,15 @@ def terminate(self):
241
246
self .cleanup () # pylint: disable=no-member
242
247
return self .active_pipe_returncode
243
248
244
- def popen ( self , * args , ** kwargs ):
249
+ def popen (self , * args , ** kwargs ):
245
250
"""Return a Popen() object in node's namespace
246
251
args: Popen() args, single list, or string
247
252
kwargs: Popen() keyword args"""
248
253
# -t is necessary to prevent docker from buffering output. It might cause
249
254
# problems with some commands like shells that then assume they can output
250
255
# all sorts of crazy control characters b/c it's a terminal.
251
- mncmd = [ 'docker' , 'exec' , '--env' , 'TERM=dumb' , '-t' , self .container ]
252
- pipe = Host .popen ( self , mncmd = mncmd , * args , ** kwargs )
256
+ mncmd = ['docker' , 'exec' , '--env' , 'TERM=dumb' , '-t' , self .container ]
257
+ pipe = Host .popen (self , mncmd = mncmd , * args , ** kwargs )
253
258
if pipe :
254
259
debug ('docker pid %d: %s %s %s' % (pipe .pid , mncmd , args , kwargs ))
255
260
return pipe
@@ -259,7 +264,7 @@ def _popen(self, cmd, **params):
259
264
# a normal interactive terminal would. So, put it in a separate process group
260
265
# so it doesn't receive stray SIGINTs, rather relying on the message sent
261
266
# from the owning process through the pty.
262
- if not 'preexec_fn' in params :
267
+ if 'preexec_fn' not in params :
263
268
params ['preexec_fn' ] = os .setpgrp
264
269
pipe = super (DockerHost , self )._popen (cmd , ** params )
265
270
if pipe :
0 commit comments