Class: LiveConsole
- Inherits:
-
Object
- Object
- LiveConsole
- Includes:
- Socket::Constants
- Defined in:
- lib/live_console.rb
Overview
LiveConsole provides a socket that can be connected to via netcat or telnet to use to connect to an IRB session inside a running process. It listens on the specified address/port or Unix Domain Socket path, and presents connecting clients with an IRB shell. Using this, you can execute code on a running instance of a Ruby process to inspect the state or even patch code on the fly.
Defined Under Namespace
Modules: IOMethods
Instance Attribute Summary collapse
-
#authenticate ⇒ Object
readonly
Returns the value of attribute authenticate.
-
#bind ⇒ Object
Returns the value of attribute bind.
-
#io ⇒ Object
readonly
Returns the value of attribute io.
-
#io_method ⇒ Object
readonly
Returns the value of attribute io_method.
-
#readline ⇒ Object
readonly
Returns the value of attribute readline.
-
#thread ⇒ Object
readonly
Returns the value of attribute thread.
Instance Method Summary collapse
-
#initialize(io_method, opts = {}) ⇒ LiveConsole
constructor
call-seq: Bind a LiveConsole to localhost:3030 (only allow clients on this machine to connect): LiveConsole.new :socket, :port => 3030 Accept connections from anywhere on port 3030.
-
#restart ⇒ Object
Restarts.
-
#start ⇒ Object
LiveConsole#start spawns a thread to listen for, accept, and provide an IRB console to new connections.
-
#start_blocking ⇒ Object
LiveConsole#start_blocking executes a loop to listen for, accept, and provide an IRB console to new connections.
-
#stop ⇒ Object
Ends the running thread, if it exists.
Constructor Details
#initialize(io_method, opts = {}) ⇒ LiveConsole
call-seq: Bind a LiveConsole to localhost:3030 (only allow clients on this machine to connect): LiveConsole.new :socket, :port => 3030 Accept connections from anywhere on port 3030. Ridiculously insecure: LiveConsole.new(:socket, :port => 3030, :host => ‘0.0.0.0’) Accept connections from anywhere on port 3030, secured with a plain-text credentials file credentials_file should be of the form: username: <username> password: <password> LiveConsole.new(:socket, :port => 3030, :host => ‘0.0.0.0’, :authenticate=>true,
:credentials_file='/path/to/.consoleaccess)
Use a Unix Domain Socket (which is more secure) instead: LiveConsole.new(:unix_socket, :path => ‘/tmp/my_liveconsole.sock’,
:mode => 0600, :uid => Process.uid, :gid => Process.gid)
By default, the mode is 0600, and the uid and gid are those of the current process. These three options are for the file’s permissions. You can also supply a binding for IRB’s toplevel: LiveConsole.new(:unix_socket, :path => “/tmp/live_console_#Process.pid.sock”, :bind => binding)
Creates a new LiveConsole. You must next call LiveConsole#start or LiveConsole#start_blocking when you want to accept connections and start the console.
47 48 49 50 51 52 53 54 55 56 |
# File 'lib/live_console.rb', line 47 def initialize(io_method, opts = {}) self.io_method = io_method.to_sym self.bind = opts.delete :bind self.authenticate = opts.delete :authenticate self.readline = opts.delete :readline unless IOMethods::List.include?(self.io_method) raise ArgumentError, "Unknown IO method: #{io_method}" end init_io opts end |
Instance Attribute Details
#authenticate ⇒ Object
Returns the value of attribute authenticate.
21 22 23 |
# File 'lib/live_console.rb', line 21 def authenticate @authenticate end |
#bind ⇒ Object
Returns the value of attribute bind.
21 22 23 |
# File 'lib/live_console.rb', line 21 def bind @bind end |
#io ⇒ Object
Returns the value of attribute io.
21 22 23 |
# File 'lib/live_console.rb', line 21 def io @io end |
#io_method ⇒ Object
Returns the value of attribute io_method.
21 22 23 |
# File 'lib/live_console.rb', line 21 def io_method @io_method end |
#readline ⇒ Object
Returns the value of attribute readline.
21 22 23 |
# File 'lib/live_console.rb', line 21 def readline @readline end |
#thread ⇒ Object
Returns the value of attribute thread.
21 22 23 |
# File 'lib/live_console.rb', line 21 def thread @thread end |
Instance Method Details
#restart ⇒ Object
Restarts. Useful for binding changes. Return value is the same as for LiveConsole#start.
133 134 135 136 137 138 139 140 |
# File 'lib/live_console.rb', line 133 def restart r = lambda { stop; start } if thread == Thread.current Thread.new &r # Leaks a thread, but works. else r.call end end |
#start ⇒ Object
LiveConsole#start spawns a thread to listen for, accept, and provide an IRB console to new connections. If a thread is already running, this method simply returns false; otherwise, it returns the new thread.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/live_console.rb', line 61 def start if thread if thread.alive? return false else thread.join self.thread = nil end end self.thread = Thread.new { start_blocking } thread end |
#start_blocking ⇒ Object
LiveConsole#start_blocking executes a loop to listen for, accept, and provide an IRB console to new connections. This is a blocking call and the only way to stop it is to kill the process
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/live_console.rb', line 80 def start_blocking loop { conn = io.get_connection #This will block until a connection is made or a failure occurs if conn.start #fork a new process for the session to redirect stdout/stderr pid = fork { begin start_irb = true if authenticate && !conn.authenticate conn.stop start_irb = false end if start_irb irb_io = GenericIOMethod.new conn.raw_input, conn.raw_output, readline begin IRB.start_with_io(irb_io, bind) rescue Errno::EPIPE => e conn.stop end end rescue Exception => e puts "Error during connection: #{e.}" conn.stop end } Process.detach(pid) end } end |
#stop ⇒ Object
Ends the running thread, if it exists. Returns true if a thread was running, false otherwise.
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/live_console.rb', line 113 def stop if thread if thread == Thread.current self.thread = nil Thread.current.exit! end thread.exit if thread.join(0.1).nil? thread.exit! end self.thread = nil true else false end end |