diff --git a/docs/configuration.md b/docs/configuration.md index 3ad67f3..c37f26b 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -394,7 +394,9 @@ and connect to it using debugpy. The usage pattern is to hit ``, enter `host` (the host where your app runs), `account` (the account it runs under), and `port` (a port that will be opened on -the remote host). Vimspector then orchestrates the various tools to set you up. +the remote host). Vimspector also supports exec'ing into Docker run containers +with `container` (the container name or id your app is running in). +Vimspector then orchestrates the various tools to set you up. ```json @@ -403,9 +405,10 @@ the remote host). Vimspector then orchestrates the various tools to set you up. "python-remote": { "port": "${port}", "host": "${host}", + "container": "${container}", "launch": { "remote": { - "host": "${host}", // Remote host to ssh to (mandatory) + "host": "${host}", // Remote host to ssh to (mandatory if not using container) "account": "${account}", // User to connect as (optional) // Optional.... Manual additional arguments for ssh @@ -432,14 +435,7 @@ the remote host). Vimspector then orchestrates the various tools to set you up. }, "attach": { "remote": { - "host": "${host}", // Remote host to ssh to (mandatory) - "account": "${account}", // User to connect as (optional) - - // Optional.... Manual additional arguments for ssh - // "ssh": { - // "args": [ "-o", "StrictHostKeyChecking=no" ] - // }, - + "container": "${container}" // Command to get the PID of the process to attach (mandatory) "pidCommand": [ // diff --git a/docs/schema/vimspector.schema.json b/docs/schema/vimspector.schema.json index ace8589..c8af196 100644 --- a/docs/schema/vimspector.schema.json +++ b/docs/schema/vimspector.schema.json @@ -78,8 +78,19 @@ "properties": { "remote": { "type": "object", - "required": [ "host" ], - "description": "Configures how Vimspector will marshal remote debugging requests. When remote debugging, Vimspector will ssh to 'account'@'host' and run 'pidCommand', 'attachCommands', 'runCommands', etc. based on the 'remote-command' option in the debug configuration. If 'remote-command' is 'launch', it runs 'runCommand(s)', otherwise (it's 'attach') vimspector runs 'pidCommand', followed by 'attachCommand(s)'.Then it starts up the debug adapter with the debug configuration as normal. Usually this is configured with an 'attach' request (whether we remotely 'launched' or not). Once the initialization exchange is complete, Vimspector runs the optional 'initCompleteCommand' which can be used to force the application to break, e.g. by sending it SIGINT. This is required on some platforms which have buggy gdbservers (for example)", + "oneOf": [ + { + "required": [ + "host" + ] + }, + { + "required": [ + "container" + ] + } + ], + "description": "Configures how Vimspector will marshal remote debugging requests. When remote debugging, Vimspector will either ssh to 'account'@'host' or docker exec -it to 'container' and run 'pidCommand', 'attachCommands', 'runCommands', etc. based on the 'remote-command' option in the debug configuration. If 'remote-command' is 'launch', it runs 'runCommand(s)', otherwise (it's 'attach') vimspector runs 'pidCommand', followed by 'attachCommand(s)'.Then it starts up the debug adapter with the debug configuration as normal. Usually this is configured with an 'attach' request (whether we remotely 'launched' or not). Once the initialization exchange is complete, Vimspector runs the optional 'initCompleteCommand' which can be used to force the application to break, e.g. by sending it SIGINT. This is required on some platforms which have buggy gdbservers (for example)", "properties": { "account": { "type": "string", @@ -87,7 +98,11 @@ }, "host": { "type": "string", - "description": "Name of the remote host to connect to (via passwordless SSH). " + "description": "Name of the remote host to connect to (via passwordless SSH)." + }, + "container": { + "type": "string", + "description": "Name or container id of the docker run container to connect to (via docker exec -it)." }, "pidCommand": { "type": "array", diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index c434c5a..14dca64 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -613,13 +613,13 @@ class DebugSession( object ): # e.g. expand variables when we use them, not all at once. This would # remove the whole %PID% hack. remote = atttach_config[ 'remote' ] - ssh = self._GetSSHCommand( remote ) + attach_cmd = self._GetAttachCommand( remote ) # FIXME: Why does this not use self._GetCommands ? - cmd = ssh + remote[ 'pidCommand' ] + pid_cmd = attach_cmd + remote[ 'pidCommand' ] - self._logger.debug( 'Getting PID: %s', cmd ) - pid = subprocess.check_output( cmd ).decode( 'utf-8' ).strip() + self._logger.debug( 'Getting PID: %s', pid_cmd ) + pid = subprocess.check_output( pid_cmd ).decode( 'utf-8' ).strip() self._logger.debug( 'Got PID: %s', pid ) if not pid: @@ -628,7 +628,7 @@ class DebugSession( object ): return if 'initCompleteCommand' in remote: - initcmd = ssh + remote[ 'initCompleteCommand' ][ : ] + initcmd = attach_cmd + remote[ 'initCompleteCommand' ][ : ] for index, item in enumerate( initcmd ): initcmd[ index ] = item.replace( '%PID%', pid ) @@ -638,7 +638,7 @@ class DebugSession( object ): commands = self._GetCommands( remote, 'attach' ) for command in commands: - cmd = ssh + command[ : ] + cmd = attach_cmd + command[ : ] for index, item in enumerate( cmd ): cmd[ index ] = item.replace( '%PID%', pid ) @@ -665,11 +665,11 @@ class DebugSession( object ): if 'remote' in run_config: remote = run_config[ 'remote' ] - ssh = self._GetSSHCommand( remote ) + attach_cmd = self._GetAttachCommand( remote ) commands = self._GetCommands( remote, 'run' ) for index, command in enumerate( commands ): - cmd = ssh + command[ : ] + cmd = attach_cmd + command[ : ] full_cmd = [] for item in cmd: if isinstance( command_line, list ): @@ -694,6 +694,20 @@ class DebugSession( object ): return ssh + def _GetDockerCommand( self, remote ): + docker = [ 'docker exec -it' ] + remote.get( 'docker', {} ).get( 'args', [] ) + if 'container' not in remote: + raise ValueError( "Invalid container; must be string" ) + docker.append( remote[ 'container' ] ) + return docker + + def _GetAttachCommand( self, remote ): + if any( remote.get( 'ssh' ), remote.get( 'account' ), remote.get( 'host' ) ): + return self._GetSSHCommand( remote ) + elif any( remote.get( 'docker' ), remote.get( 'container' ) ): + return self._GetDockerCommand( remote ) + raise ValueError( 'Could not determine attach command' ) + def _GetCommands( self, remote, pfx ): commands = remote.get( pfx + 'Commands', None )