def _internal_connect(self, server, timeout, share=False): """Connect to the remote host provided via an ssh port forward. An SSH process is fired with port forwarding established on localhost 22181, which the zookeeper client connects to. :param server: Remote host to connect to, specified as hostname:port :type string :param timeout: An timeout interval in seconds. :type float Returns a connected client or error. """ hostname, port = self._parse_servers(server or self._servers) start_time = time.time() # Determine which port we'll be using. local_port = get_open_port() port_watcher = PortWatcher("localhost", local_port, timeout) tunnel_error = Deferred() # On a tunnel error, stop the port watch early and bail with error. tunnel_error.addErrback(port_watcher.stop) # If a tunnel error happens now or later, close the connection. tunnel_error.addErrback(lambda x: self.close()) # Setup tunnel via an ssh process for port forwarding. protocol = ClientTunnelProtocol(self, tunnel_error) self._process = forward_port( self.remote_user, local_port, hostname, int(port), process_protocol=protocol, share=share) # Wait for the tunneled port to open. try: yield port_watcher.async_wait() except socket.error: self.close() # Stop the tunnel process. raise ConnectionTimeoutException("could not connect") else: # If we stopped because of a tunnel error, raise it. if protocol.error: yield tunnel_error # Check timeout new_timeout = timeout - (time.time() - start_time) if new_timeout <= 0: self.close() raise ConnectionTimeoutException( "could not connect before timeout") # Connect the client try: yield super(SSHClient, self).connect( "localhost:%d" % local_port, new_timeout) except: self.close() # Stop the tunnel raise returnValue(self)
def test_connect_with_key(self): """ A private key path can optionally be specified as an argument to connect in which case its passed to the ssh command line. """ from twisted.internet import reactor file_path = self.makeFile("content") mock_reactor = self.mocker.patch(reactor) mock_reactor.spawnProcess(ARGS, KWARGS) saved = [] self.mocker.call(lambda *args, **kwargs: saved.append((args, kwargs))) self.mocker.result("the-process") self.mocker.replay() result = forward_port("ubuntu", 22181, "remote_host", 2181, private_key_path=file_path) self.assertEquals(result, "the-process") args, kwargs = saved[0] self.assertIsInstance(args[0], TunnelProtocol) self.assertEquals(args[1], "/usr/bin/ssh") self.assertEquals(args[2], [ "ssh", "-T", "-i", file_path, "-o", "ControlPath " + self.home + "/.juju/ssh/master-%r@%h:%p", "-o", "ControlMaster no", "-o", "PasswordAuthentication no", "-Llocalhost:22181:localhost:2181", "ubuntu@remote_host"]) self.assertEquals(kwargs, {"env": os.environ})
def test_ssh_spawn(self): """ Forwarding a port spawns an ssh process with port forwarding arguments. """ from twisted.internet import reactor mock_reactor = self.mocker.patch(reactor) mock_reactor.spawnProcess(ARGS, KWARGS) saved = [] self.mocker.call(lambda *args, **kwargs: saved.append((args, kwargs))) self.mocker.result(None) self.mocker.replay() result = forward_port("ubuntu", 8888, "remote_host", 9999) self.assertEquals(result, None) self.assertTrue(saved) args, kwargs = saved[0] self.assertIsInstance(args[0], TunnelProtocol) self.assertEquals(args[1], "/usr/bin/ssh") self.assertEquals(args[2], [ "ssh", "-T", "-o", "ControlPath " + self.home + "/.juju/ssh/master-%r@%h:%p", "-o", "ControlMaster no", "-o", "PasswordAuthentication no", "-Llocalhost:8888:localhost:9999", "ubuntu@remote_host"]) self.assertEquals(kwargs, {"env": os.environ})
def test_ssh_spawn_sharing(self): """ When sharing is enabled, ssh will be set up so that it becomes the master if there's no other master alive yet. """ from twisted.internet import reactor mock_reactor = self.mocker.patch(reactor) mock_reactor.spawnProcess(ARGS, KWARGS) saved = [] self.mocker.call(lambda *args, **kwargs: saved.append((args, kwargs))) self.mocker.result(None) self.mocker.replay() result = forward_port("ubuntu", 8888, "remote_host", 9999, share=True) self.assertEquals(result, None) self.assertTrue(saved) args, kwargs = saved[0] self.assertIsInstance(args[0], TunnelProtocol) self.assertEquals(args[1], "/usr/bin/ssh") self.assertEquals(args[2], [ "ssh", "-T", "-o", "ControlPath " + self.home + "/.juju/ssh/master-%r@%h:%p", "-o", "ControlMaster auto", "-o", "PasswordAuthentication no", "-Llocalhost:8888:localhost:9999", "ubuntu@remote_host"]) self.assertEquals(kwargs, {"env": os.environ})
def _internal_connect(self, server, timeout, share=False): """Connect to the remote host provided via an ssh port forward. An SSH process is fired with port forwarding established on localhost 22181, which the zookeeper client connects to. :param server: Remote host to connect to, specified as hostname:port :type string :param timeout: An timeout interval in seconds. :type float Returns a connected client or error. """ hostname, port = self._parse_servers(server or self._servers) start_time = time.time() # Determine which port we'll be using. local_port = get_open_port() port_watcher = PortWatcher("localhost", local_port, timeout) tunnel_error = Deferred() # On a tunnel error, stop the port watch early and bail with error. tunnel_error.addErrback(port_watcher.stop) # If a tunnel error happens now or later, close the connection. tunnel_error.addErrback(lambda x: self.close()) # Setup tunnel via an ssh process for port forwarding. protocol = ClientTunnelProtocol(self, tunnel_error) self._process = forward_port(self.remote_user, local_port, hostname, int(port), process_protocol=protocol, share=share) # Wait for the tunneled port to open. try: yield port_watcher.async_wait() except socket.error: self.close() # Stop the tunnel process. raise ConnectionTimeoutException("could not connect") else: # If we stopped because of a tunnel error, raise it. if protocol.error: yield tunnel_error # Check timeout new_timeout = timeout - (time.time() - start_time) if new_timeout <= 0: self.close() raise ConnectionTimeoutException( "could not connect before timeout") # Connect the client try: yield super(SSHClient, self).connect("localhost:%d" % local_port, new_timeout) except: self.close() # Stop the tunnel raise returnValue(self)