Open a tunnel between localhost:local_port and remote_host:remote_port via the host specified by this context.

        Remember to close() the returned "tunnel" object in order to clean up
        after yourself when you are done with the tunnel.

def tunnel(self, local_port, remote_port=None, remote_host="localhost"):
        """
        Open a tunnel between localhost:local_port and remote_host:remote_port via the host specified by this context.

        Remember to close() the returned "tunnel" object in order to clean up
        after yourself when you are done with the tunnel.
        """
        tunnel_host = "{0}:{1}:{2}".format(local_port, remote_host, remote_port)
        proc = self.Popen(
            # cat so we can shut down gracefully by closing stdin
            ["-L", tunnel_host, "echo -n ready && cat"],
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
        )
        # make sure to get the data so we know the connection is established
        ready = proc.stdout.read(5)
        assert ready == b"ready", "Didn't get ready from remote echo"
        yield  # user code executed here
        proc.communicate()
        assert proc.returncode == 0, "Tunnel process did an unclean exit (returncode %s)" % (proc.returncode,)