From 6b7c5b09af43356e18809402db2735bbb3b5155d Mon Sep 17 00:00:00 2001 From: Xingyao Wang Date: Mon, 8 Apr 2024 21:34:07 +0800 Subject: [PATCH] fix(sandbox): Fix docker root login and set default to run-as-devin (#891) * support execute as-root for sandbox * set run as devin by default to true * get network_mode = host back * Update opendevin/sandbox/sandbox.py Co-authored-by: Anas DORBANI <95044293+dorbanianas@users.noreply.github.com> * print login info for debugging * use ssh -v instead of ssh * change port map to 2222 to circumvent the MacOS issue * add warning message for port forwarding --------- Co-authored-by: Anas DORBANI <95044293+dorbanianas@users.noreply.github.com> --- opendevin/sandbox/sandbox.py | 75 +++++++++++++++++++++++++++++------- 1 file changed, 62 insertions(+), 13 deletions(-) diff --git a/opendevin/sandbox/sandbox.py b/opendevin/sandbox/sandbox.py index edc6689927..abc40bd661 100644 --- a/opendevin/sandbox/sandbox.py +++ b/opendevin/sandbox/sandbox.py @@ -4,9 +4,10 @@ import select import sys import time import uuid +import platform from pexpect import pxssh from collections import namedtuple -from typing import Dict, List, Tuple +from typing import Dict, List, Tuple, Union import docker @@ -134,26 +135,53 @@ class DockerInteractive(CommandExecutor): self.restart_docker_container() # set up random user password self._ssh_password = str(uuid.uuid4()) - if RUN_AS_DEVIN: - self.setup_devin_user() - self.start_ssh_session() - else: - # TODO: implement ssh into root - raise NotImplementedError( - 'Running as root is not supported at the moment.') + self.setup_user() + self.start_ssh_session() atexit.register(self.cleanup) - def setup_devin_user(self): + def setup_user(self): + # Check if the opendevin user exists + exit_code, logs = self.container.exec_run( + ['/bin/bash', '-c', 'id -u opendevin'], + workdir='/workspace', + ) + if exit_code == 0: + # User exists, delete it + exit_code, logs = self.container.exec_run( + ['/bin/bash', '-c', 'userdel -r opendevin'], + workdir='/workspace', + ) + if exit_code != 0: + raise Exception( + f'Failed to remove opendevin user in sandbox: {logs}') + + # Create the opendevin user exit_code, logs = self.container.exec_run( ['/bin/bash', '-c', f'useradd -rm -d /home/opendevin -s /bin/bash -g root -G sudo -u {USER_ID} opendevin'], workdir='/workspace', ) + if exit_code != 0: + raise Exception( + f'Failed to create opendevin user in sandbox: {logs}') exit_code, logs = self.container.exec_run( ['/bin/bash', '-c', f"echo 'opendevin:{self._ssh_password}' | chpasswd"], workdir='/workspace', ) + if exit_code != 0: + raise Exception(f'Failed to set password in sandbox: {logs}') + + if not RUN_AS_DEVIN: + exit_code, logs = self.container.exec_run( + # change password for root + ['/bin/bash', '-c', + f"echo 'root:{self._ssh_password}' | chpasswd"], + workdir='/workspace', + ) + if exit_code != 0: + raise Exception( + f'Failed to set password for root in sandbox: {logs}') exit_code, logs = self.container.exec_run( ['/bin/bash', '-c', "echo 'opendevin-sandbox' > /etc/hostname"], workdir='/workspace', @@ -163,7 +191,13 @@ class DockerInteractive(CommandExecutor): # start ssh session at the background self.ssh = pxssh.pxssh() hostname = 'localhost' - username = 'opendevin' + if RUN_AS_DEVIN: + username = 'opendevin' + else: + username = 'root' + logger.info( + f"Connecting to {username}@{hostname} via ssh. If you encounter any issues, you can try `ssh -v -p 2222 {username}@{hostname}` with the password '{self._ssh_password}' and report the issue on GitHub." + ) self.ssh.login(hostname, username, self._ssh_password, port=2222) # Fix: https://github.com/pexpect/pexpect/issues/669 @@ -292,12 +326,25 @@ class DockerInteractive(CommandExecutor): # Initialize docker client. Throws an exception if Docker is not reachable. docker_client = docker.from_env() + network_kwargs: Dict[str, Union[str, Dict[str, int]]] = {} + if platform.system() == 'Linux': + network_kwargs['network_mode'] = 'host' + elif platform.system() == 'Darwin': + # FIXME: This is a temporary workaround for Mac OS + network_kwargs['ports'] = {'2222/tcp': 2222} + logger.warning( + ('Using port forwarding for Mac OS. ' + 'Server started by OpenDevin will not be accessible from the host machine at the moment. ' + 'See https://github.com/OpenDevin/OpenDevin/issues/897 for more information.' + ) + ) + # start the container self.container = docker_client.containers.run( self.container_image, - # only allow connections from localhost - command="/usr/sbin/sshd -D -p 2222 -o 'ListenAddress=0.0.0.0'", - ports={'2222/tcp': 2222}, + # allow root login + command="/usr/sbin/sshd -D -p 2222 -o 'PermitRootLogin=yes'", + **network_kwargs, working_dir='/workspace', name=self.container_name, hostname='opendevin_sandbox', @@ -321,6 +368,8 @@ class DockerInteractive(CommandExecutor): time.sleep(1) elapsed += 1 self.container = docker_client.containers.get(self.container_name) + logger.info( + f'waiting for container to start: {elapsed}, container status: {self.container.status}') if elapsed > self.timeout: break if self.container.status != 'running':