def _run_docker_container(self, runflags): """ Create & run job container, install klio packages as editable, and attach to the container with an interactive terminal. """ container = self._docker_client.containers.create(**runflags) container.start() def run_and_log(cmd): _, output = container.exec_run(cmd, tty=True, stream=True) for line in output: try: self._docker_logger.info(line.decode("utf-8").strip("\n")) except Exception: # sometimes there's a decode error for a log line, but it # shouldn't stop the setup pass run_and_log("pip install --upgrade pip setuptools") for pkg in self.install_pkgs: run_and_log(self.PIP_CMD.format(pkg=pkg)) # need to use lower-level Docker API client in order to start # an interactive terminal inside the running container self._docker_logger.info( "\nConnecting to job's container. Use CTRL+C to stop.") pty_client = docker.APIClient(base_url="unix://var/run/docker.sock") dockerpty.start(pty_client, container.attrs)
def start(self, projectname): dataMap = self.get_settings() current_directory = os.getcwd() data_folder = Path("osdp") file_to_open = data_folder / "projects" / dataMap['osdp']['project'] / dataMap['osdp']['platform'] final_directory = os.path.join(current_directory, file_to_open) if not os.path.exists(final_directory): print("This should have already been created") exit() if dataMap['osdp']['platform'] == 'vagrant': vagrant_folder = Path(final_directory) v = vagrant.Vagrant(vagrant_folder, quiet_stdout=False) try: v.up() except Exception as e: pass os.chdir(vagrant_folder) cmdCommand = "vagrant port" process = subprocess.Popen(cmdCommand.split(), stdout=subprocess.PIPE) output, error = process.communicate() print(output) elif dataMap['osdp']['platform'] == 'docker': print("Ths platform is docker and we will connect to the image") os.chdir(final_directory) retval = os.getcwd() IMG_SRC = dataMap['osdp']['dockerdeveloperimage'] client = docker.Client() client.login(username=dataMap['osdp']['dockerhubusername'], password=dataMap['osdp']['dockerhubpassword'], registry="https://index.docker.io/v1/") client.pull(IMG_SRC) client.tag(image=dataMap['osdp']['dockerdeveloperimage'], repository=dataMap['osdp']['pushto'],tag=dataMap['osdp']['runtime']) response = [line for line in client.push(dataMap['osdp']['pushto'] + ":" + dataMap['osdp']['runtime'], stream=True)] container_id = client.create_container('buildmystartup/ghettolabs:python3.6',stdin_open=True,tty=True,command='/bin/bash', volumes=['/home/user/environments/osdp/osdp/projects/ghettolabs/docker'],host_config=client.create_host_config \ (binds=['/home/user/environments/osdp/osdp/projects/ghettolabs/docker:/var/task',])) dockerpty.start(client, container_id)
def step_impl(ctx): pid, fd = pty.fork() if pid == pty.CHILD: tty = os.ttyname(0) sys.stdin = open(tty, 'r') sys.stdout = open(tty, 'w') sys.stderr = open(tty, 'w') try: dockerpty.start(ctx.client, ctx.container) except Exception as e: raise e os._exit(1) else: os._exit(0) else: tty = os.ttyname(fd) ctx.pty = fd util.set_pty_size( ctx.pty, (ctx.rows, ctx.cols) ) ctx.pid = pid util.wait(ctx.pty, timeout=5)
def resurrect_shell(self, container=None, env=None): if container is None: container = self.current_task.container if env is None: env = self.current_task.env # once the command is stopped, there's no getting it back without # running the command again, but we can commit to an image image = container.commit( changes="LABEL {}={}".format(LABEL_BUILD_ID, "@temporary") ) self._extra_images.append(image) try: container = self.docker_client.containers.create( image=image, labels={LABEL_BUILD_ID: "@temporary"}, working_dir=self.work_dir, stdin_open=True, environment=["{}={}".format(*p) for p in env.items()], tty=True, command="/bin/bash" # XXX This is a guess! ) self._all_containers.append(container) try: dockerpty.start(self.docker_client.api, container.id) finally: container.stop() finally: self.cleanup()
def step_impl(ctx): pid, fd = pty.fork() if pid == pty.CHILD: tty = os.ttyname(0) sys.stdin = open(tty, 'r') sys.stdout = open(tty, 'w') sys.stderr = open(tty, 'w') try: dockerpty.start(ctx.client, ctx.container) except Exception as e: raise e os._exit(1) else: os._exit(0) else: tty = os.ttyname(fd) ctx.pty = fd util.set_pty_size( ctx.pty, (ctx.rows, ctx.cols) ) ctx.pid = pid util.wait(ctx.pty, timeout=5) time.sleep(1) # give the terminal some time to print prompt
def run_command(self, command): # type: (str) -> None if self.shell: to_run = shlex.split( self.shell) + [command] # type: Union[str, List[str]] console.progress("(%s)> %s" % (self.shell, command)) else: to_run = command console.progress("> %s" % command) container = self.service.create_container(one_off=True, command=to_run, tty=False, stdin_open=True, detach=False) try: dockerpty.start(self.client, container.id, interactive=False) if container.wait() != 0: raise BuildFailedException() sys.exit(1) finally: self.client.remove_container(container.id, force=True)
def run(self, project, options): """ Run a one-off command on a service. For example: $ fig run web python manage.py shell By default, linked services will be started, unless they are already running. If you do not want to start linked services, use `fig run --no-deps SERVICE COMMAND [ARGS...]`. Usage: run [options] SERVICE [COMMAND] [ARGS...] Options: -d Detached mode: Run container in the background, print new container name. -T Disable pseudo-tty allocation. By default `fig run` allocates a TTY. --rm Remove container after run. Ignored in detached mode. --no-deps Don't start linked services. """ service = project.get_service(options['SERVICE']) if not options['--no-deps']: deps = service.get_linked_names() if len(deps) > 0: project.up( service_names=deps, start_links=True, recreate=False, ) tty = True if options['-d'] or options['-T'] or not sys.stdin.isatty(): tty = False if options['COMMAND']: command = [options['COMMAND']] + options['ARGS'] else: command = service.options.get('command') container_options = { 'command': command, 'tty': tty, 'stdin_open': not options['-d'], } container = service.create_container(one_off=True, **container_options) if options['-d']: service.start_container(container, ports=None, one_off=True) print(container.name) else: service.start_container(container, ports=None, one_off=True) dockerpty.start(project.client, container.id) exit_code = container.wait() if options['--rm']: log.info("Removing %s..." % container.name) project.client.remove_container(container.id) sys.exit(exit_code)
def __call__(self, *args, **kwargs): cli = self.swarm.client if cli is not None: rm_flag = kwargs.pop('rm') logs = kwargs.pop('logs') try: ret = cli.create_container(*args, **kwargs) if ret.get('Warnings') is not None: print('[Warning] {message}'.format(message=ret['Warnings'])) # try to start created container if ret.get('Id') is not None: if kwargs['stdin_open'] and kwargs['tty']: dockerpty.start(cli, ret['Id'], logs=logs) else: cli.start(ret['Id']) print(ret['Id']) if rm_flag: cli.remove_container(ret['Id']) except (errors.NotFound, errors.APIError, errors.DockerException) as e: pyprint(e.explanation) # volumes_from and dns arguments raise TypeError exception # if they are used against v1.10 and above of the Docker remote API except TypeError as e: pyprint(e) finally: cli.close()
def debug(arg_list): cwd = os.getcwd() cli = get_cli() image_name = "%s:%s" % (container_repo, container_tag()) bind_dirs = mount_volumes() container_data = cli.create_container(image=image_name, command=arg_list, host_config=cli.create_host_config( port_bindings={3333:3333}, network_mode='host', binds=bind_dirs ), working_dir=cwd, tty=True, stdin_open=True, ports=[3333]) container_id = container_data['Id'].encode('utf8') if container_data['Warnings']: print "Warnings: ", container_data['Warnings'] if sys.platform.startswith('darwin'): darwin_debug(arg_list, bind_dirs) else: dockerpty.start(cli, container_id) cli.stop(container_id) cli.remove_container(container_id)
def install(): loader = PackageLoader() package = loader.load(os.getcwd()) client_factory = DockerClientFactory() client = client_factory.get_client() container = client.create_container( image=package.current_image, stdin_open=True, tty=True, command="pip install flask", working_dir=MOUNT_DIRECTORY, host_config=client.create_host_config(binds={ os.getcwd(): { "bind": MOUNT_DIRECTORY, "mode": "rw" } }) ) dockerpty.start(client, container) # Update package image package.current_image = client.commit(container.get("Id")).get("Id") loader.save(os.getcwd(), package)
def step_impl(ctx): pid, fd = pty.fork() if pid == pty.CHILD: tty = os.ttyname(0) sys.stdin = open(tty, 'r') sys.stdout = open(tty, 'w') sys.stderr = open(tty, 'w') try: dockerpty.start(ctx.client, ctx.container) except Exception as e: raise e os._exit(1) else: os._exit(0) else: try: tty = os.ttyname(fd) except OSError as ex: # Not supported on OS X. But since we're not using this # TTY name anyway, let the test pass. tty = 'OSX' ctx.pty = fd util.set_pty_size( ctx.pty, (ctx.rows, ctx.cols) ) ctx.pid = pid util.wait(ctx.pty, timeout=5) time.sleep(1) # give the terminal some time to print prompt
def attach(self): if not self.container(): sys.stderr.write("Error: container does not exist\n") sys.exit(1) dockerpty.start( self.c, self.c.inspect_container(self.config.hostname))
def eval_command(self, args): """Start containers""" if (args["detach"] is False) and (args["tty"]): dockerpty.start(self.client, self.settings["create"], interactive=args["stdin_open"]) else: self.client.start(self.settings["create"])
def _start(self): self._log.info("Starting container: {0}".format(self._cobj.id)) if self._isatty(): dockerpty.start(self._dc.api, self._cobj.id) else: self._cobj.start() ret = self._cobj.wait() self._log.info("Container {0} stopped and returned {1}".format(self._cobj.id, ret['StatusCode']))
def docker_run( docker_client, image_id, command, project_root, environment_variables, platform_config_paths=[], ): exit_status = 0 output = 'Done' try: volumes = { project_root: { 'bind': project_root, 'mode': 'rw', }, '/var/run/docker.sock': { 'bind': '/var/run/docker.sock', 'mode': 'ro', } } for platform_config_path in platform_config_paths: volumes[platform_config_path] = { 'bind': platform_config_path, 'mode': 'ro', } if _command(command) == 'shell': columns = int(check_output(['tput', 'cols'])) lines = int(check_output(['tput', 'lines'])) environment_variables['COLUMNS'] = columns environment_variables['LINES'] = lines container = docker_client.containers.create( image_id, command=command, environment=environment_variables, volumes=volumes, working_dir=project_root, tty=True, stdin_open=True, ) dockerpty.start(docker_client.api, container.id) output = 'Shell end' else: container = docker_client.containers.run( image_id, command=command, environment=environment_variables, detach=True, volumes=volumes, working_dir=project_root, ) _print_logs(container) return handle_finished_container(container) except DockerException as error: exit_status = 1 output = str(error) return exit_status, output
def detection(): path = current_directory + '/detection/' name = 'crosswalk_detection' volume = current_directory + 'crosswalks:/crosswalks/' build_container_if_not_exist(path, name + ':latest') if shutil.which('nvidia-docker'): remove_container_if_exist(name) subprocess.run('nvidia-docker run -it -v ' + volume + ' -t ' + name + ' ' + name + ' bash') else: container = create_container_if_not_exist(image=name, volumes=volume, name=name, tty=True, stdin_open=True) dockerpty.start(client, container)
def run_one_off_container(container_options, project, service, options): if not options['--no-deps']: deps = service.get_linked_service_names() if deps: project.up( service_names=deps, start_deps=True, strategy=ConvergenceStrategy.never) if project.use_networking: project.ensure_network_exists() try: container = service.create_container( quiet=True, one_off=True, **container_options) except APIError: legacy.check_for_legacy_containers( project.client, project.name, [service.name], allow_one_off=False) raise if options['-d']: container.start() print(container.name) return def remove_container(force=False): if options['--rm']: project.client.remove_container(container.id, force=True) def force_shutdown(signal, frame): project.client.kill(container.id) remove_container(force=True) sys.exit(2) def shutdown(signal, frame): set_signal_handler(force_shutdown) project.client.stop(container.id) remove_container() sys.exit(1) set_signal_handler(shutdown) dockerpty.start(project.client, container.id, interactive=not options['-T']) exit_code = container.wait() remove_container() sys.exit(exit_code)
def _run_interactive_container(self, image, docker_args, container_id): try: docker_container = self.docker_client.containers.create( image, **docker_args) self.printer.print_launch_container(container_id, launched_ok=True, is_interactive=True) dockerpty.start(self.docker_client.api, docker_container.id) self.printer.print_stop_container(container_id, stopped_ok=True) except Exception as e: self.printer.print_launch_container(container_id, launched_ok=False, is_interactive=True) self.printer.print_error("{}".format(e)) return
def sandbox_file_in_container(image, command, file_path): if not docker_client.images(name=image): """empty""" docker_client.pull(image) directory = _find_dir(str(file_path)) image = docker_client.create_container(image=image, working_dir=directory, volumes=[directory], host_config=docker_client.create_host_config(binds=[ directory + ':' + directory, ]), stdin_open=True, tty=True, command=command) dockerpty.start(docker_client, image) docker_client.remove_container(image)
def run_one_off_container(container_options, project, service, options): if not options['--no-deps']: deps = service.get_linked_service_names() if deps: project.up(service_names=deps, start_deps=True, strategy=ConvergenceStrategy.never) if project.use_networking: project.ensure_network_exists() try: container = service.create_container(quiet=True, one_off=True, **container_options) except APIError: legacy.check_for_legacy_containers(project.client, project.name, [service.name], allow_one_off=False) raise if options['-d']: container.start() print(container.name) return def remove_container(force=False): if options['--rm']: project.client.remove_container(container.id, force=True) def force_shutdown(signal, frame): project.client.kill(container.id) remove_container(force=True) sys.exit(2) def shutdown(signal, frame): set_signal_handler(force_shutdown) project.client.stop(container.id) remove_container() sys.exit(1) set_signal_handler(shutdown) dockerpty.start(project.client, container.id, interactive=not options['-T']) exit_code = container.wait() remove_container() sys.exit(exit_code)
def run_pty( self, image: str, *, # enforce the rest as kwargs command: str = DEFAULT_PTY_COMMAND, environment: Optional[List[models.Environment]] = None, network: Optional[str] = None, ports: Optional[List[models.Port]] = None, remove: bool = True, volumes: Optional[List[models.Volume]] = None): """ Runs a docker container and spawns an interactive shell over a pseudo terminal. Args: image: The docker container will be built from this image command: The command to run on the docker container. This command should spawn a shell and defaults to /bin/bash environment: List of environment variables that the container will use network: The network that the container will connect to ports: List of ports that the container will expose remove: Removes container after running the command, defaults to True volumes: List of volumes that the container will mount """ try: container = self._docker_client.containers.create( image=image, command=command, volumes=_volume_strings_from_collection(volumes), environment=_environment_from_collection(environment), network_mode=network, ports=_port_bindings_from_collection(ports), tty=True, stdin_open=True, ) except docker.errors.DockerException as e: raise ContainerError( "Unable to create container: {}".format(e)) from e # Attempt to start docker pty try: dockerpty.start(self._docker_client.api, {"Id": container.id}) except Exception as e: raise ContainerPtyError( "Unable to start a PTY terminal: {}".format(e)) from e finally: if remove: _remove_container(container)
def run_command(self, command): console.progress("> %s" % command) container = self.service.create_container(one_off=True, command=command, tty=False, stdin_open=True, detach=False) try: dockerpty.start(self.client, container.id, interactive=False) if container.wait() != 0: console.error("\nBuild Failed.") sys.exit(1) finally: self.client.remove_container(container.id, force=True)
def start(self, projectname): dataMap = self.get_settings() current_directory = os.getcwd() data_folder = Path("osdp") file_to_open = data_folder / "projects" / dataMap['osdp'][ 'project'] / dataMap['osdp']['platform'] self.final_directory = os.path.join(current_directory, file_to_open) if not os.path.exists(self.final_directory): print("This should have already been created") self.build() if dataMap['osdp']['platform'] == 'vagrant': messages.send_message( dataMap['osdp']['username'] + " " + "Just started a vagrant box for Python Development") vagrant_folder = Path(self.final_directory) v = vagrant.Vagrant(vagrant_folder, quiet_stdout=False) try: v.up() except Exception as e: print("Please open a github issue if you have a problem") os.chdir(vagrant_folder) cmdCommand = "vagrant port" process = subprocess.Popen(cmdCommand.split(), stdout=subprocess.PIPE) output, error = process.communicate() print(output) subprocess.run(["vagrant", "ssh"]) elif dataMap['osdp']['platform'] == 'docker': print("Ths platform is docker and we will connect to the image") os.chdir(self.final_directory) retval = os.getcwd() IMG_SRC = dataMap['osdp']['dockerdeveloperimage'] client = docker.Client() # Uncomment if working with a private image #client.login(username=dataMap['osdp']['dockerhubusername'], password=dataMap['osdp']['dockerhubpassword'], registry="https://index.docker.io/v1/") client.pull(IMG_SRC) #client.tag(image=dataMap['osdp']['dockerdeveloperimage'], repository=dataMap['osdp']['pushto'],tag=dataMap['osdp']['runtime']) #response = [line for line in client.push(dataMap['osdp']['pushto'] + ":" + dataMap['osdp']['runtime'], stream=True)] container_id = client.create_container(dataMap['osdp']['imagename'],stdin_open=True,tty=True,command='/bin/bash', volumes=dataMap['osdp']['dockerhome'],host_config=client.create_host_config \ # Need to adjust this for mac users - change /Users to /home (binds=[dataMap['osdp']['dockerhome'] + ':' + '/home',])) #(binds=['/home:/home',])) dockerpty.start(client, container_id)
def run_command(self, command): console.progress("> %s" % command) container = self.service.create_container( one_off=True, command=command, tty=False, stdin_open=True, detach=False) try: dockerpty.start(self.client, container.id, interactive=False) if container.wait() != 0: raise BuildFailedException() sys.exit(1) finally: self.client.remove_container(container.id, force=True)
def run_one_off_container(container_options, project, service, options): if not options['--no-deps']: deps = service.get_linked_service_names() if deps: project.up( service_names=deps, start_deps=True, strategy=ConvergenceStrategy.never) project.initialize_networks() container = service.create_container( quiet=True, one_off=True, **container_options) if options['-d']: service.start_container(container) print(container.name) return def remove_container(force=False): if options['--rm']: project.client.remove_container(container.id, force=True) signals.set_signal_handler_to_shutdown() try: try: dockerpty.start(project.client, container.id, interactive=not options['-T']) service.connect_container_to_networks(container) exit_code = container.wait() except signals.ShutdownException: project.client.stop(container.id) exit_code = 1 except signals.ShutdownException: project.client.kill(container.id) remove_container(force=True) sys.exit(2) remove_container() sys.exit(exit_code)
def run(): loader = PackageLoader() package = loader.load(os.getcwd()) client_factory = DockerClientFactory() client = client_factory.get_client() container = client.create_container( image=package.current_image, stdin_open=True, tty=True, command="python {}".format(package.entry_point), working_dir=MOUNT_DIRECTORY, host_config=client.create_host_config(binds={ os.getcwd(): { "bind": MOUNT_DIRECTORY, "mode": "rw" } }) ) dockerpty.start(client, container)
def run(self, step): """Execute the given step in docker.""" cid = pu.sanitized_name(step.id, self._config.wid) container = self._find_container(cid) if not container and self._config.reuse: log.fail( f"Cannot find an existing container for step '{step.id}' to be reused" ) if container and not self._config.reuse and not self._config.dry_run: container.remove(force=True) container = None if not container and not self._config.reuse: container = self._create_container(cid, step) log.info(f"[{step.id}] docker start") if self._config.dry_run: return 0 self._spawned_containers.add(container) try: container.start() if self._config.pty: dockerpty.start(self._d.api, container.id) else: cout = container.logs(stream=True) for line in cout: log.step_info(line.decode().rstrip()) e = container.wait()["StatusCode"] except Exception as exc: log.fail(exc) return e
def __call__(self, *args, **kwargs): cli = self.swarm.client if cli is not None: rm_flag = kwargs.pop('rm') try: ret = cli.create_container(*args, **kwargs) if ret.get('Warnings') is not None: print('[Warning] {message}'.format(message=ret['Warnings'])) # try to start created container if ret.get('Id') is not None: if kwargs['stdin_open'] and kwargs['tty']: dockerpty.start(cli, ret['Id']) else: cli.start(ret['Id']) # try to get the latest container # check if container id is matched # otherwise search containers since=self.container['Id'] latest_container = cli.containers(latest=True)[0] if ret['Id'] == latest_container['Id']: self._get_containers(latest=True) else: self._get_containers(since=ret['Id'], container_list=(ret['Id'],)) self._pretty_print() if rm_flag: cli.remove_container(ret['Id']) except errors.NotFound as e: print(e.explanation) except errors.APIError as e: print(e.explanation) except errors.DockerException as e: print(e.explanation) # volumes_from and dns arguments raise TypeError exception # if they are used against v1.10 and above of the Docker remote API except TypeError as e: print(e) finally: cli.close()
def step_impl(ctx): pid, fd = pty.fork() if pid == pty.CHILD: tty = os.ttyname(0) sys.stdin = open(tty, 'r') sys.stdout = open(tty, 'w') sys.stderr = open(tty, 'w') try: dockerpty.start(ctx.client, ctx.container) except: os_.exit(1) os._exit(0) else: tty = os.ttyname(fd) ctx.pty = fd util.set_pty_size( ctx.pty, (ctx.rows, ctx.cols) ) ctx.pid = pid util.wait(ctx.pty)
def run(self, project, options): """ Run a one-off command on a service. For example: $ docker-compose run web python manage.py shell By default, linked services will be started, unless they are already running. If you do not want to start linked services, use `docker-compose run --no-deps SERVICE COMMAND [ARGS...]`. Usage: run [options] [-e KEY=VAL...] SERVICE [COMMAND] [ARGS...] Options: --allow-insecure-ssl Allow insecure connections to the docker registry -d Detached mode: Run container in the background, print new container name. --entrypoint CMD Override the entrypoint of the image. -e KEY=VAL Set an environment variable (can be used multiple times) -u, --user="" Run as specified username or uid --no-deps Don't start linked services. --rm Remove container after run. Ignored in detached mode. --service-ports Run command with the service's ports enabled and mapped to the host. -T Disable pseudo-tty allocation. By default `docker-compose run` allocates a TTY. """ service = project.get_service(options['SERVICE']) insecure_registry = options['--allow-insecure-ssl'] if not options['--no-deps']: deps = service.get_linked_names() if len(deps) > 0: project.up(service_names=deps, start_deps=True, recreate=False, insecure_registry=insecure_registry, detach=options['-d']) tty = True if options['-d'] or options['-T'] or not sys.stdin.isatty(): tty = False if options['COMMAND']: command = [options['COMMAND']] + options['ARGS'] else: command = service.options.get('command') container_options = { 'command': command, 'tty': tty, 'stdin_open': not options['-d'], 'detach': options['-d'], } if options['-e']: # Merge environment from config with -e command line container_options['environment'] = dict( parse_environment(service.options.get('environment')), **parse_environment(options['-e'])) if options['--entrypoint']: container_options['entrypoint'] = options.get('--entrypoint') if options['--user']: container_options['user'] = options.get('--user') if not options['--service-ports']: container_options['ports'] = [] container = service.create_container( one_off=True, insecure_registry=insecure_registry, **container_options) if options['-d']: service.start_container(container) print(container.name) else: service.start_container(container) dockerpty.start(project.client, container.id, interactive=not options['-T']) exit_code = container.wait() if options['--rm']: log.info("Removing %s..." % container.name) project.client.remove_container(container.id) sys.exit(exit_code)
def open(self): lgr.debug("Opening TTY connection to docker container.") # TODO: probably call to super to assure that we have it running? dockerpty.start(self.client, self.container, logs=0)
def run(self, project, options): """ Run a one-off command on a service. For example: $ docker-compose run web python manage.py shell By default, linked services will be started, unless they are already running. If you do not want to start linked services, use `docker-compose run --no-deps SERVICE COMMAND [ARGS...]`. Usage: run [options] [-e KEY=VAL...] SERVICE [COMMAND] [ARGS...] Options: --allow-insecure-ssl Allow insecure connections to the docker registry -d Detached mode: Run container in the background, print new container name. --entrypoint CMD Override the entrypoint of the image. -e KEY=VAL Set an environment variable (can be used multiple times) -u, --user="" Run as specified username or uid --no-deps Don't start linked services. --rm Remove container after run. Ignored in detached mode. --service-ports Run command with the service's ports enabled and mapped to the host. -T Disable pseudo-tty allocation. By default `docker-compose run` allocates a TTY. """ service = project.get_service(options['SERVICE']) insecure_registry = options['--allow-insecure-ssl'] if not options['--no-deps']: deps = service.get_linked_names() if len(deps) > 0: project.up( service_names=deps, start_deps=True, recreate=False, insecure_registry=insecure_registry, detach=options['-d'] ) tty = True if options['-d'] or options['-T'] or not sys.stdin.isatty(): tty = False if options['COMMAND']: command = [options['COMMAND']] + options['ARGS'] else: command = service.options.get('command') container_options = { 'command': command, 'tty': tty, 'stdin_open': not options['-d'], 'detach': options['-d'], } if options['-e']: # Merge environment from config with -e command line container_options['environment'] = dict( parse_environment(service.options.get('environment')), **parse_environment(options['-e'])) if options['--entrypoint']: container_options['entrypoint'] = options.get('--entrypoint') if options['--rm']: container_options['restart'] = None if options['--user']: container_options['user'] = options.get('--user') if not options['--service-ports']: container_options['ports'] = [] container = service.create_container( one_off=True, insecure_registry=insecure_registry, **container_options ) if options['-d']: service.start_container(container) print(container.name) else: service.start_container(container) dockerpty.start(project.client, container.id, interactive=not options['-T']) exit_code = container.wait() if options['--rm']: log.info("Removing %s..." % container.name) project.client.remove_container(container.id) sys.exit(exit_code)
def _run_container(self, name, image_name, container_name , detach=False, command=None, tty=True, volumes=None, volumes_from=None, links=None, delete_on_exit=False, env=None, ports=None, dependency=False, no_intervention=False ): """Run a single container""" if not detach and dependency: tty = True log.info("Creating container from %s\timage=%s\tcontainer_name=%s\ttty=%s", image_name, name, container_name, tty) binds = {} volume_names = [] if volumes is None: volumes = [] uncreated = [] for volume in volumes: if ":" in volume: name, bound = volume.split(":", 1) permissions = "rw" if ":" in bound: bound, permissions = volume.split(":", 1) binds[name] = {"bind": bound, permissions: True} volume_names.append(bound) if not os.path.exists(name): log.info("Making volume for mounting\tvolume=%s", name) try: os.makedirs(name) except OSError as error: uncreated.append((name, error)) if uncreated: raise BadOption("Failed to create some volumes on the host", uncreated=uncreated) if volumes: log.info("\tUsing volumes\tvolumes=%s", volumes) if env: log.info("\tUsing environment\tenv=%s", env) if ports: log.info("\tUsing ports\tports=%s", ports.keys()) container = self.docker_context.create_container(image_name , name=container_name , detach=detach , command=command , volumes=volumes , environment=env , tty = tty , ports = (ports or {}).keys() , stdin_open = tty ) container_id = container if isinstance(container_id, dict): if "errorDetail" in container_id: raise BadImage("Failed to create container", image=name, error=container_id["errorDetail"]) container_id = container_id["Id"] self._container_id = container_id self.already_running = True try: log.info("Starting container %s", container_name) if links: log.info("\tLinks: %s", links) if volumes_from: log.info("\tVolumes from: %s", volumes_from) if ports: log.info("\tPort Bindings: %s", ports) self.docker_context.start(container_id , links = links , binds = binds , volumes_from = volumes_from , port_bindings = ports ) if not detach and not dependency: try: dockerpty.start(self.docker_context, container_id) except KeyboardInterrupt: pass inspection = None if not detach and not dependency: for _ in until(timeout=0.5, step=0.1, silent=True): try: inspection = self.docker_context.inspect_container(container_id) if not isinstance(inspection, dict) or "State" not in inspection: raise BadResult("Expected inspect result to be a dictionary with 'State' in it", found=inspection) elif not inspection["State"]["Running"]: break except Exception as error: log.error("Failed to see if container exited normally or not\thash=%s\terror=%s", container_id, error) if inspection and not no_intervention: if not inspection["State"]["Running"] and inspection["State"]["ExitCode"] != 0: if self.interactive and not self.heira_formatted("harpoon.no_intervention", default=False): print("!!!!") print("Failed to run the container!") print("Do you want commit the container in it's current state and /bin/bash into it to debug?") answer = raw_input("[y]: ") if not answer or answer.lower().startswith("y"): with self.commit_and_run(container_id, command="/bin/bash"): pass raise BadImage("Failed to run container", container_id=container_id, container_name=container_name) finally: if delete_on_exit: self._stop_container(container_id, container_name)
def run_with_pty(self, interactive: bool = False) -> int: dockerpty.start(self._client.api, self._container.id, interactive=interactive, logs=True) exit_code = self.get_exit_code() self._container.remove() return exit_code
def execute(self): # prepare container_working_dir = self.cfg.env.container_working_dir working_dir = ( pathlib.Path(self.cfg.global_config.working_dir).absolute().as_posix() ) try: # linux/mac import dockerpty container = self.docker_cli.containers.create( name=self.cfg.env.name, image=self.cfg.env.image, command=self.cfg.env.entry_point, working_dir=container_working_dir, volumes={working_dir: {"bind": container_working_dir, "mode": "rw"}}, auto_remove=True, # required tty=True, stdin_open=True, ) dockerpty.start(self.docker_cli.api, container.id) except ImportError: # windows # i have no better idea now logout( "Your system does not support pty. Trying to use command line instead ..." ) command = [ "docker", "run", "-i", # remove after usage "--rm", # workspace "-v", f"{working_dir}:{container_working_dir}", "-w", container_working_dir, "--name", self.cfg.env.name, # image self.cfg.env.image, # interface self.cfg.env.entry_point, ] logout(f"start env: {command}") process = subprocess.Popen(command, stdin=subprocess.PIPE) try: while True: user_input = input() user_input += "\n" process.stdin.write(user_input.encode()) process.stdin.flush() except KeyboardInterrupt: process.kill() finally: # end, stop it self.docker_cli.api.stop(self.cfg.env.name) logout("devcube end.")
def run(docker, path, variables, yamls): """run a new container, using a predefined yaml""" allowed_paths = [] if path is not None: for element in path.split(os.pathsep): allowed_paths.append(os.path.normcase(os.path.abspath(element))) for docker_file_name in yamls: # Check if the docker yaml file is in an allowed path if len(allowed_paths) > 0: # no path given, look in allowed path and use it as the file name # path is checked any way, to resolve symbolic links if os.path.basename(docker_file_name) == docker_file_name: for element in allowed_paths: if os.path.exists(element + os.sep + docker_file_name): # use that as the new file name docker_file_name = element + os.sep + docker_file_name break # Resolve to a absolute real path # symbolic links are resolve too real_file_name = os.path.normcase(os.path.realpath(docker_file_name)) valid = False for element in allowed_paths: if os.path.commonprefix([element, real_file_name]) == element: valid = True if not valid: print >> sys.stderr, "invalid yaml container: %s" % docker_file_name return 1 # Load the yaml docker file with open(docker_file_name, 'r') as docker_file: try: docker_conf = yaml.safe_load(docker_file) except (yaml.scanner.ScannerError, yaml.parser.ParserError) as e: print >> sys.stderr, e return 1 # Match variables against the filters for (key, value) in docker_conf.pop('check', {}).items(): if key not in variables: print >> sys.stderr, "undefined variable '%s'" % key return 1 #The variable check is a string, the filter is a regex if type(value) == str or type(value) == unicode: if re.match("^" + value + "$", variables[key]) is None: print >> sys.stderr, "variable %s not a valid value: '%s'" % (key, variables[key]) return 1 # it's a list, search in allowed values elif type(value) == list: if not variables[key] in value: print >> sys.stderr, "variable %s not an allowed value" % key return 1 # resolve variables expression for (var, expression) in docker_conf.pop('variables', {}).items(): try: variables[var] = eval(expression, {}, variables) except Exception as e: print >> sys.stderr, "evaluation failed for %s:" % (expression) for l in traceback.format_exception_only(type(e), e): print " " + l, return 1 docker_kwargs = TemplateDict(variables, docker_conf) effective_create_kwargs = {} effective_start_kwargs = {} effective_hostconfig_kwargs = {} # Converted the binding, must be given as an array of single-element hash # transformed to OrderedDict, docker-py expect a dict if 'binds' in docker_kwargs: binds = docker_kwargs['binds'] if not isinstance(binds, list): print >> sys.stderr, "binding must be an array" return 1 new_binds = collections.OrderedDict() for bind in binds: (key, value) = bind.items()[0] # now inverse the source and destination # the docker api is incoherent between port bind and mount bind source_binding = value.pop('bind', key) value['bind'] = key new_binds[source_binding] = value docker_kwargs['binds'] = new_binds # if a script is given, save it as a temporary file if 'script' in docker_kwargs: script = docker_kwargs.pop('script') with tempfile.NamedTemporaryFile(delete=False) as script_file: script_file.write(script) script_file.flush() os.chmod(script_file.name, (stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) & ~stat.S_IWUSR & ~stat.S_IWGRP & ~stat.S_IWOTH) docker_kwargs['command'] = [script_file.name] if 'binds' not in docker_kwargs: docker_kwargs['binds'] = collections.OrderedDict() docker_kwargs['binds'][script_file.name] = {'bind': script_file.name, 'ro': True} do_attach = not docker_kwargs.pop('detach', False) docker_kwargs['tty'] = do_attach docker_kwargs['stdin_open'] = do_attach do_rm = docker_kwargs.pop('rm', False) # list of capability to drop or add if 'cap_drop' in docker_kwargs and isinstance(docker_kwargs['cap_drop'], list): effective_start_kwargs['cap_drop'] = docker_kwargs.pop('cap_drop') if 'cap_add' in docker_kwargs and isinstance(docker_kwargs['cap_drop'], list): effective_start_kwargs['cap_add'] = docker_kwargs.pop('cap_add') # some exceptions, given in create_container, should be used in start: if 'volumes_from' in docker_kwargs: effective_hostconfig_kwargs['volumes_from'] = docker_kwargs.pop('volumes_from') if 'dns' in docker_kwargs: effective_hostconfig_kwargs['dns'] = docker_kwargs.pop('dns') # needs to manage port binding # it's dict of mapping # valid values for key is d+((-d+)|,d+)?(|tcp|udp) # valid values for destination is None, port, or a array of [host, port] # If a range was given, auto-increment destination if 'port_bindings' in docker_kwargs: effective_create_kwargs['ports'] = [] port_bindings = {} for (port, port_definition) in docker_kwargs.pop('port_bindings').items(): # If nothing, just a direct mapping if port_definition is None: proto = "tcp" listen_host = None listen_ports = (port, ) # if a plain integer, a one to one mapping elif type(port_definition) == int: proto = "tcp" listen_host = None listen_ports = (port_definition, ) else: proto = port_definition.pop('protocol', 'tcp') listen_host = port_definition.pop('host', None) listen_range = port_definition.pop('range', None) listen_ports = port_definition.pop('port', None) if listen_ports is None and range is None: listen_ports = (port, ) elif listen_ports is not None and listen_range is not None: print >> sys.stderr, "port mapping %d given both range and port" % port return 1 elif listen_ports is not None: listen_ports = (listen_ports, ) elif listen_range is not None: # we got a range # it's start,count if listen_range.rfind(",") > 0: listen_range = listen_range.split(",") listen_ports = range(int(listen_range[0]), int(listen_range[0]) + int(listen_range[1])) # or it start-stop elif listen_range.rfind("-") > 0: listen_range = listen_range.split("-") listen_ports = range(int(listen_range[0]), int(listen_range[1]) + 1) else: print >> sys.stderr, "port mapping %d given neither range and port" % port return 1 for listen_port in listen_ports: effective_create_kwargs['ports'].append((port, proto)) port_bindings["%d/%s" %(port, proto)] = (listen_host, listen_port) port += 1 effective_hostconfig_kwargs['port_bindings'] = port_bindings # Extract argument for hostconfig for arg_name in inspect.getargspec(dockerlib.utils.create_host_config).args: if arg_name in docker_kwargs: effective_hostconfig_kwargs[arg_name] = docker_kwargs.pop(arg_name) effective_create_kwargs['host_config'] = dockerlib.utils.create_host_config(**effective_hostconfig_kwargs) #start with 1, 0 is 'self' for arg_name in inspect.getargspec(dockerlib.Client.create_container).args[1:]: if arg_name in docker_kwargs: effective_create_kwargs[arg_name] = docker_kwargs.pop(arg_name) #start with 1, 0 is 'self' for arg_name in inspect.getargspec(dockerlib.Client.start).args[1:]: if arg_name in docker_kwargs: effective_start_kwargs[arg_name] = docker_kwargs.pop(arg_name) # don' forget to store the container creator if not 'environment' in effective_create_kwargs: effective_create_kwargs['environment'] = {} effective_create_kwargs['environment']['CONTAINER_CREATOR'] = variables['environment.SUDO_USER'] # is a numeric id given for the user, or is it needed to resolve it ? if 'user' in effective_create_kwargs and not isinstance(effective_create_kwargs['user'], (int, long)): user = effective_create_kwargs['user'] try: effective_create_kwargs['user'] = getpwnam(user).pw_uid except KeyError: print >> sys.stderr, "user '%s' not found" % user return 1 if len(docker_kwargs) > 0: print >> sys.stderr, "invalid argument: %s" % docker_kwargs return 1 container = docker.create_container(**effective_create_kwargs) if container['Warnings'] is not None: print >> sys.stderr, "warning: %s" % container.Warnings if do_attach: try: dockerpty.start(docker, container, **effective_start_kwargs) if do_rm: docker.remove_container(container, v=True) except dockerlib.errors.APIError as e: print >> sys.stderr, e except socket.error: print >> sys.stderr, "container detached" else: docker.start(container, **effective_start_kwargs) return 0
def handler(): dockerpty.start(self.host.client, container_pointer) self.host.client.remove_container(container_pointer)
#!/usr/bin/env python import dockerpty import os from docker.client import Client from docker.utils import kwargs_from_env client = Client(base_url=os.environ['DOCKER_HOST'], version=os.environ['DOCKER_SERVER_API_VERSION']) container = client.create_container(image="debian:wheezy", stdin_open=True, tty=True, command='echo "passed"') dockerpty.start(client, container)
def execute_tests_in_container( distro_name: str, docker_tag: str, version: CMKVersion, result_path: Path, command: List[str], interactive: bool, ) -> int: client = _docker_client() info = client.info() logger.info("Docker version: %s", info["ServerVersion"]) base_image_name = "%s/%s" % (_DOCKER_REGISTRY, distro_name) image_name_with_tag = _create_cmk_image(client, base_image_name, docker_tag, version) # Start the container with _start( client, image=image_name_with_tag, command="/bin/bash", volumes=list(_runtime_volumes().keys()), host_config=client.api.create_host_config( # Create some init process that manages signals and processes init=True, # needed to make the overlay mounts work on the /git directory # Should work, but does not seem to be enough: 'cap_add=["SYS_ADMIN"]'. Using this instead: privileged=True, # Important to workaround really high default of docker which results # in problems when trying to close all FDs in Python 2. ulimits=[ docker.types.Ulimit(name="nofile", soft=2048, hard=2048), ], binds=[ ":".join([k, v["bind"], v["mode"]]) for k, v in _runtime_volumes().items() ], # Our SNMP integration tests need SNMP. For this reason we enable the IPv6 support # docker daemon wide, but set some fixed local network which is not being routed. # This makes it possible to use IPv6 on the "lo" interface. Externally IPv4 is used sysctls={ "net.ipv6.conf.eth0.disable_ipv6": 1, }, ), stdin_open=True, tty=True, ) as container: # Ensure we can make changes to the git directory (not persisting it outside of the container) _prepare_git_overlay(container, "/git-lowerdir", "/git") _cleanup_previous_virtual_environment(container, version) _reuse_persisted_virtual_environment(container, version) if interactive: logger.info("+-------------------------------------------------") logger.info("| Next steps:") logger.info("| ") logger.info("| /git/scripts/run-pipenv shell") logger.info("| cd /git") logger.info("| ") logger.info("| ... start whatever test you want, for example:") logger.info("| ") logger.info("| make -C tests test-integration") logger.info("| ") logger.info("| Execute all integration tests") logger.info("| ") logger.info("| tests/scripts/run-integration-test.py " "tests/integration/livestatus/test_livestatus.py") logger.info("| ") logger.info("| Execute some integration tests") logger.info("| ") logger.info("| tests/scripts/run-integration-test.py " "tests/integration/livestatus/test_livestatus.py " "-k test_service_custom_variables ") logger.info("| ") logger.info("| Execute a single test") logger.info("| ") logger.info("+-------------------------------------------------") dockerpty.start(client.api, container.id) return 0 # Now execute the real test in the container context exit_code = _exec_run( container, command, environment=_container_env(version), workdir="/git", stream=True, ) # Collect the test results located in /results of the container. The # jenkins job will make it available as artifact later _copy_directory(container, Path("/results"), result_path) return exit_code
def run(docker, path, variables, yamls): """run a new container, using a predefined yaml""" allowed_paths = [] if path is not None: for element in path.split(os.pathsep): allowed_paths.append(os.path.normcase(os.path.abspath(element))) for docker_file_name in yamls: # Check if the docker yaml file is in an allowed path if len(allowed_paths) > 0: # no path given, look in allowed path and use it as the file name # path is checked any way, to resolve symbolic links if os.path.basename(docker_file_name) == docker_file_name: for element in allowed_paths: if os.path.exists(element + os.sep + docker_file_name): # use that as the new file name docker_file_name = element + os.sep + docker_file_name break # Resolve to a absolute real path # symbolic links are resolve too real_file_name = os.path.normcase( os.path.realpath(docker_file_name)) valid = False for element in allowed_paths: if os.path.commonprefix([element, real_file_name]) == element: valid = True if not valid: print >> sys.stderr, "invalid yaml container: %s" % docker_file_name return 1 # Load the yaml docker file with open(docker_file_name, 'r') as docker_file: try: docker_conf = yaml.safe_load(docker_file) except (yaml.scanner.ScannerError, yaml.parser.ParserError) as e: print >> sys.stderr, e return 1 # Match variables against the filters for (key, value) in docker_conf.pop('check', {}).items(): if key not in variables: print >> sys.stderr, "undefined variable '%s'" % key return 1 #The variable check is a string, the filter is a regex if type(value) == str or type(value) == unicode: if re.match("^" + value + "$", variables[key]) is None: print >> sys.stderr, "variable %s not a valid value: '%s'" % ( key, variables[key]) return 1 # it's a list, search in allowed values elif type(value) == list: if not variables[key] in value: print >> sys.stderr, "variable %s not an allowed value" % key return 1 # resolve variables expression for (var, expression) in docker_conf.pop('variables', {}).items(): try: variables[var] = eval(expression, {}, variables) except Exception as e: print >> sys.stderr, "evaluation failed for %s:" % (expression) for l in traceback.format_exception_only(type(e), e): print " " + l, return 1 docker_kwargs = TemplateDict(variables, docker_conf) effective_create_kwargs = {} effective_start_kwargs = {} effective_hostconfig_kwargs = {} # Converted the binding, must be given as an array of single-element hash # transformed to OrderedDict, docker-py expect a dict if 'binds' in docker_kwargs: binds = docker_kwargs['binds'] if not isinstance(binds, list): print >> sys.stderr, "binding must be an array" return 1 new_binds = collections.OrderedDict() for bind in binds: (key, value) = bind.items()[0] # now inverse the source and destination # the docker api is incoherent between port bind and mount bind source_binding = value.pop('bind', key) value['bind'] = key new_binds[source_binding] = value docker_kwargs['binds'] = new_binds # if a script is given, save it as a temporary file if 'script' in docker_kwargs: script = docker_kwargs.pop('script') with tempfile.NamedTemporaryFile(delete=False) as script_file: script_file.write(script) script_file.flush() os.chmod(script_file.name, (stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) & ~stat.S_IWUSR & ~stat.S_IWGRP & ~stat.S_IWOTH) docker_kwargs['command'] = [script_file.name] if 'binds' not in docker_kwargs: docker_kwargs['binds'] = collections.OrderedDict() docker_kwargs['binds'][script_file.name] = { 'bind': script_file.name, 'ro': True } do_attach = not docker_kwargs.pop('detach', False) docker_kwargs['tty'] = do_attach docker_kwargs['stdin_open'] = do_attach do_rm = docker_kwargs.pop('rm', False) # list of capability to drop or add if 'cap_drop' in docker_kwargs and isinstance( docker_kwargs['cap_drop'], list): effective_start_kwargs['cap_drop'] = docker_kwargs.pop('cap_drop') if 'cap_add' in docker_kwargs and isinstance(docker_kwargs['cap_drop'], list): effective_start_kwargs['cap_add'] = docker_kwargs.pop('cap_add') # some exceptions, given in create_container, should be used in start: if 'volumes_from' in docker_kwargs: effective_hostconfig_kwargs['volumes_from'] = docker_kwargs.pop( 'volumes_from') if 'dns' in docker_kwargs: effective_hostconfig_kwargs['dns'] = docker_kwargs.pop('dns') # needs to manage port binding # it's dict of mapping # valid values for key is d+((-d+)|,d+)?(|tcp|udp) # valid values for destination is None, port, or a array of [host, port] # If a range was given, auto-increment destination if 'port_bindings' in docker_kwargs: effective_create_kwargs['ports'] = [] port_bindings = {} for (port, port_definition ) in docker_kwargs.pop('port_bindings').items(): # If nothing, just a direct mapping if port_definition is None: proto = "tcp" listen_host = None listen_ports = (port, ) # if a plain integer, a one to one mapping elif type(port_definition) == int: proto = "tcp" listen_host = None listen_ports = (port_definition, ) else: proto = port_definition.pop('protocol', 'tcp') listen_host = port_definition.pop('host', None) listen_range = port_definition.pop('range', None) listen_ports = port_definition.pop('port', None) if listen_ports is None and range is None: listen_ports = (port, ) elif listen_ports is not None and listen_range is not None: print >> sys.stderr, "port mapping %d given both range and port" % port return 1 elif listen_ports is not None: listen_ports = (listen_ports, ) elif listen_range is not None: # we got a range # it's start,count if listen_range.rfind(",") > 0: listen_range = listen_range.split(",") listen_ports = range( int(listen_range[0]), int(listen_range[0]) + int(listen_range[1])) # or it start-stop elif listen_range.rfind("-") > 0: listen_range = listen_range.split("-") listen_ports = range(int(listen_range[0]), int(listen_range[1]) + 1) else: print >> sys.stderr, "port mapping %d given neither range and port" % port return 1 for listen_port in listen_ports: effective_create_kwargs['ports'].append((port, proto)) port_bindings["%d/%s" % (port, proto)] = (listen_host, listen_port) port += 1 effective_hostconfig_kwargs['port_bindings'] = port_bindings # Extract argument for hostconfig for arg_name in inspect.getargspec( dockerlib.utils.create_host_config).args: if arg_name in docker_kwargs: effective_hostconfig_kwargs[arg_name] = docker_kwargs.pop( arg_name) effective_create_kwargs[ 'host_config'] = dockerlib.utils.create_host_config( **effective_hostconfig_kwargs) #start with 1, 0 is 'self' for arg_name in inspect.getargspec( dockerlib.Client.create_container).args[1:]: if arg_name in docker_kwargs: effective_create_kwargs[arg_name] = docker_kwargs.pop(arg_name) #start with 1, 0 is 'self' for arg_name in inspect.getargspec(dockerlib.Client.start).args[1:]: if arg_name in docker_kwargs: effective_start_kwargs[arg_name] = docker_kwargs.pop(arg_name) # don' forget to store the container creator if not 'environment' in effective_create_kwargs: effective_create_kwargs['environment'] = {} effective_create_kwargs['environment'][ 'CONTAINER_CREATOR'] = variables['environment.SUDO_USER'] # is a numeric id given for the user, or is it needed to resolve it ? if 'user' in effective_create_kwargs and not isinstance( effective_create_kwargs['user'], (int, long)): user = effective_create_kwargs['user'] try: effective_create_kwargs['user'] = getpwnam(user).pw_uid except KeyError: print >> sys.stderr, "user '%s' not found" % user return 1 if len(docker_kwargs) > 0: print >> sys.stderr, "invalid argument: %s" % docker_kwargs return 1 container = docker.create_container(**effective_create_kwargs) if container['Warnings'] is not None: print >> sys.stderr, "warning: %s" % container.Warnings if do_attach: try: dockerpty.start(docker, container, **effective_start_kwargs) if do_rm: docker.remove_container(container, v=True) except dockerlib.errors.APIError as e: print >> sys.stderr, e except socket.error: print >> sys.stderr, "container detached" else: docker.start(container, **effective_start_kwargs) return 0
import docker import dockerpty c = docker.Client(base_url='unix://var/run/docker.sock') container_id = c.create_container( image='ubuntu:14.04', stdin_open=True, tty=True, command='/bin/bash' ) dockerpty.start(c, container_id)
def run(self, options): """ :param options: :return: """ if options.entrypoint == "runtest": raise ValueError( "You cannot use the entrypoint 'runtest' in interactive mode!") try: # prepare the Docker image (updating it if required) docker_image = self.get_image_name(options, options.skip_update) # volumes vmounts, volumes = self._parse_volumes(options.volume) # ports ports = self._parse_ports(options.port) # environment environment = [ "GALAXY_URL={0}".format(options.server), "GALAXY_API_KEY={0}".format(options.api_key) ] # command command = [ options.entrypoint, "--server", options.server, "--api-key", options.api_key ] if "web_port" in options: command.extend(["--port", "{}".format(options.web_port)]) import socket # create and run Docker containers client = _docker.APIClient() container = client.create_container( image=docker_image, stdin_open=True, tty=True, hostname=socket.gethostname(), command=command, environment=environment, volumes=vmounts, ports=list(ports.keys()), host_config=client.create_host_config(binds=volumes, port_bindings=ports)) _logger.info("Started Docker container %s", container["Id"]) _dockerpty.start(client, container) client.remove_container(container["Id"]) _logger.info("Removed Docker container %s", container["Id"]) return _SUCCESS_EXIT except NameError as ne: if options and options.debug: _logger.exception(ne) print( "\n ERROR: To use wft4galaxy-docker in development mode " "you need to install 'docker' and 'dockerpty' Python libries \n" "\tType \"pip install docker dockerpty\" to install the required libraries.\n" ) return _FAILURE_EXIT except Exception as e: _logger.error( "ERROR: Unable to start the Docker container: {0}".format( str(e))) if options and options.debug: _logger.exception(e) return _FAILURE_EXIT
def run(self, project, options): """ Run a one-off command on a service. For example: $ docker-compose run web python manage.py shell By default, linked services will be started, unless they are already running. If you do not want to start linked services, use `docker-compose run --no-deps SERVICE COMMAND [ARGS...]`. Usage: run [options] [-p PORT...] [-e KEY=VAL...] SERVICE [COMMAND] [ARGS...] Options: --allow-insecure-ssl Deprecated - no effect. -d Detached mode: Run container in the background, print new container name. --name NAME Assign a name to the container --entrypoint CMD Override the entrypoint of the image. -e KEY=VAL Set an environment variable (can be used multiple times) -u, --user="" Run as specified username or uid --no-deps Don't start linked services. --rm Remove container after run. Ignored in detached mode. -p, --publish=[] Publish a container's port(s) to the host --service-ports Run command with the service's ports enabled and mapped to the host. -T Disable pseudo-tty allocation. By default `docker-compose run` allocates a TTY. """ service = project.get_service(options['SERVICE']) if options['--allow-insecure-ssl']: log.warn(INSECURE_SSL_WARNING) if not options['--no-deps']: deps = service.get_linked_service_names() if len(deps) > 0: project.up( service_names=deps, start_deps=True, strategy=ConvergenceStrategy.never, ) tty = True if options['-d'] or options['-T'] or not sys.stdin.isatty(): tty = False if options['COMMAND']: command = [options['COMMAND']] + options['ARGS'] else: command = service.options.get('command') container_options = { 'command': command, 'tty': tty, 'stdin_open': not options['-d'], 'detach': options['-d'], } if options['-e']: container_options['environment'] = parse_environment(options['-e']) if options['--entrypoint']: container_options['entrypoint'] = options.get('--entrypoint') if options['--rm']: container_options['restart'] = None if options['--user']: container_options['user'] = options.get('--user') if not options['--service-ports']: container_options['ports'] = [] if options['--publish']: container_options['ports'] = options.get('--publish') if options['--publish'] and options['--service-ports']: raise UserError( 'Service port mapping and manual port mapping ' 'can not be used togather' ) if options['--name']: container_options['name'] = options['--name'] try: container = service.create_container( quiet=True, one_off=True, **container_options ) except APIError as e: legacy.check_for_legacy_containers( project.client, project.name, [service.name], allow_one_off=False, ) raise e if options['-d']: service.start_container(container) print(container.name) else: dockerpty.start(project.client, container.id, interactive=not options['-T']) exit_code = container.wait() if options['--rm']: project.client.remove_container(container.id) sys.exit(exit_code)
def run(self, project, options): """ Run a one-off command on a service. For example: $ docker-compose run web python manage.py shell By default, linked services will be started, unless they are already running. If you do not want to start linked services, use `docker-compose run --no-deps SERVICE COMMAND [ARGS...]`. Usage: run [options] [-e KEY=VAL...] SERVICE [COMMAND] [ARGS...] Options: --allow-insecure-ssl Allow insecure connections to the docker registry -d Detached mode: Run container in the background, print new container name. --entrypoint CMD Override the entrypoint of the image. -e KEY=VAL Set an environment variable (can be used multiple times) -u, --user="" Run as specified username or uid --no-deps Don't start linked services. --rm Remove container after run. Ignored in detached mode. --service-ports Run command with the service's ports enabled and mapped to the host. -T Disable pseudo-tty allocation. By default `docker-compose run` allocates a TTY. """ service = project.get_service(options["SERVICE"]) insecure_registry = options["--allow-insecure-ssl"] if not options["--no-deps"]: deps = service.get_linked_names() if len(deps) > 0: project.up( service_names=deps, start_deps=True, allow_recreate=False, insecure_registry=insecure_registry ) tty = True if options["-d"] or options["-T"] or not sys.stdin.isatty(): tty = False if options["COMMAND"]: command = [options["COMMAND"]] + options["ARGS"] else: command = service.options.get("command") container_options = {"command": command, "tty": tty, "stdin_open": not options["-d"], "detach": options["-d"]} if options["-e"]: container_options["environment"] = parse_environment(options["-e"]) if options["--entrypoint"]: container_options["entrypoint"] = options.get("--entrypoint") if options["--rm"]: container_options["restart"] = None if options["--user"]: container_options["user"] = options.get("--user") if not options["--service-ports"]: container_options["ports"] = [] try: container = service.create_container( quiet=True, one_off=True, insecure_registry=insecure_registry, **container_options ) except APIError as e: legacy.check_for_legacy_containers(project.client, project.name, [service.name], allow_one_off=False) raise e if options["-d"]: service.start_container(container) print(container.name) else: dockerpty.start(project.client, container.id, interactive=not options["-T"]) exit_code = container.wait() if options["--rm"]: project.client.remove_container(container.id) sys.exit(exit_code)
def run(self, project, options): """ Run a one-off command on a service. For example: $ fig run web python manage.py shell By default, linked services will be started, unless they are already running. If you do not want to start linked services, use `fig run --no-deps SERVICE COMMAND [ARGS...]`. Usage: run [options] [-e KEY=VAL...] SERVICE [COMMAND] [ARGS...] Options: --allow-insecure-ssl Allow insecure connections to the docker registry -d Detached mode: Run container in the background, print new container name. --entrypoint CMD Override the entrypoint of the image. -e KEY=VAL Set an environment variable (can be used multiple times) --no-deps Don't start linked services. --rm Remove container after run. Ignored in detached mode. -T Disable pseudo-tty allocation. By default `fig run` allocates a TTY. """ service = project.get_service(options['SERVICE']) insecure_registry = options['--allow-insecure-ssl'] if not options['--no-deps']: deps = service.get_linked_names() if len(deps) > 0: project.up( service_names=deps, start_links=True, recreate=False, ) tty = True if options['-d'] or options['-T'] or not sys.stdin.isatty(): tty = False if options['COMMAND']: command = [options['COMMAND']] + options['ARGS'] else: command = service.options.get('command') container_options = { 'command': command, 'tty': tty, 'stdin_open': not options['-d'], } if options['-e']: for option in options['-e']: if 'environment' not in service.options: service.options['environment'] = {} k, v = option.split('=', 1) service.options['environment'][k] = v if options['--entrypoint']: container_options['entrypoint'] = options.get('--entrypoint') container = service.create_container( one_off=True, insecure_registry=insecure_registry, **container_options) if options['-d']: service.start_container(container, ports=None, one_off=True) print(container.name) else: service.start_container(container, ports=None, one_off=True) dockerpty.start(project.client, container.id, interactive=not options['-T']) exit_code = container.wait() if options['--rm']: log.info("Removing %s..." % container.name) project.client.remove_container(container.id) sys.exit(exit_code)
def run(self, project, options): """ Run a one-off command on a service. For example: $ docker-compose run web python manage.py shell By default, linked services will be started, unless they are already running. If you do not want to start linked services, use `docker-compose run --no-deps SERVICE COMMAND [ARGS...]`. Usage: run [options] [-p PORT...] [-e KEY=VAL...] SERVICE [COMMAND] [ARGS...] Options: --allow-insecure-ssl Deprecated - no effect. -d Detached mode: Run container in the background, print new container name. --name NAME Assign a name to the container --entrypoint CMD Override the entrypoint of the image. -e KEY=VAL Set an environment variable (can be used multiple times) -u, --user="" Run as specified username or uid --no-deps Don't start linked services. --rm Remove container after run. Ignored in detached mode. -p, --publish=[] Publish a container's port(s) to the host --service-ports Run command with the service's ports enabled and mapped to the host. -T Disable pseudo-tty allocation. By default `docker-compose run` allocates a TTY. """ service = project.get_service(options["SERVICE"]) detach = options["-d"] if IS_WINDOWS_PLATFORM and not detach: raise UserError( "Interactive mode is not yet supported on Windows.\n" "Please pass the -d flag when using `docker-compose run`." ) if options["--allow-insecure-ssl"]: log.warn(INSECURE_SSL_WARNING) if not options["--no-deps"]: deps = service.get_linked_service_names() if len(deps) > 0: project.up(service_names=deps, start_deps=True, strategy=ConvergenceStrategy.never) elif project.use_networking: project.ensure_network_exists() tty = True if detach or options["-T"] or not sys.stdin.isatty(): tty = False if options["COMMAND"]: command = [options["COMMAND"]] + options["ARGS"] else: command = service.options.get("command") container_options = {"command": command, "tty": tty, "stdin_open": not detach, "detach": detach} if options["-e"]: container_options["environment"] = parse_environment(options["-e"]) if options["--entrypoint"]: container_options["entrypoint"] = options.get("--entrypoint") if options["--rm"]: container_options["restart"] = None if options["--user"]: container_options["user"] = options.get("--user") if not options["--service-ports"]: container_options["ports"] = [] if options["--publish"]: container_options["ports"] = options.get("--publish") if options["--publish"] and options["--service-ports"]: raise UserError("Service port mapping and manual port mapping " "can not be used togather") if options["--name"]: container_options["name"] = options["--name"] try: container = service.create_container(quiet=True, one_off=True, **container_options) except APIError as e: legacy.check_for_legacy_containers(project.client, project.name, [service.name], allow_one_off=False) raise e if detach: service.start_container(container) print(container.name) else: dockerpty.start(project.client, container.id, interactive=not options["-T"]) exit_code = container.wait() if options["--rm"]: project.client.remove_container(container.id) sys.exit(exit_code)
def run(self, project, options): """ Run a one-off command on a service. For example: $ docker-compose run web python manage.py shell By default, linked services will be started, unless they are already running. If you do not want to start linked services, use `docker-compose run --no-deps SERVICE COMMAND [ARGS...]`. Usage: run [options] [-p PORT...] [-e KEY=VAL...] SERVICE [COMMAND] [ARGS...] Options: --allow-insecure-ssl Deprecated - no effect. -d Detached mode: Run container in the background, print new container name. --name NAME Assign a name to the container --entrypoint CMD Override the entrypoint of the image. -e KEY=VAL Set an environment variable (can be used multiple times) -u, --user="" Run as specified username or uid --no-deps Don't start linked services. --rm Remove container after run. Ignored in detached mode. -p, --publish=[] Publish a container's port(s) to the host --service-ports Run command with the service's ports enabled and mapped to the host. -T Disable pseudo-tty allocation. By default `docker-compose run` allocates a TTY. """ service = project.get_service(options['SERVICE']) detach = options['-d'] if IS_WINDOWS_PLATFORM and not detach: raise UserError( "Interactive mode is not yet supported on Windows.\n" "Please pass the -d flag when using `docker-compose run`.") if options['--allow-insecure-ssl']: log.warn(INSECURE_SSL_WARNING) if not options['--no-deps']: deps = service.get_linked_service_names() if len(deps) > 0: project.up( service_names=deps, start_deps=True, strategy=ConvergenceStrategy.never, ) tty = True if detach or options['-T'] or not sys.stdin.isatty(): tty = False if options['COMMAND']: command = [options['COMMAND']] + options['ARGS'] else: command = service.options.get('command') container_options = { 'command': command, 'tty': tty, 'stdin_open': not detach, 'detach': detach, } if options['-e']: container_options['environment'] = parse_environment(options['-e']) if options['--entrypoint']: container_options['entrypoint'] = options.get('--entrypoint') if options['--rm']: container_options['restart'] = None if options['--user']: container_options['user'] = options.get('--user') if not options['--service-ports']: container_options['ports'] = [] if options['--publish']: container_options['ports'] = options.get('--publish') if options['--publish'] and options['--service-ports']: raise UserError('Service port mapping and manual port mapping ' 'can not be used togather') if options['--name']: container_options['name'] = options['--name'] try: container = service.create_container(quiet=True, one_off=True, **container_options) except APIError as e: legacy.check_for_legacy_containers( project.client, project.name, [service.name], allow_one_off=False, ) raise e if detach: service.start_container(container) print(container.name) else: dockerpty.start(project.client, container.id, interactive=not options['-T']) exit_code = container.wait() if options['--rm']: project.client.remove_container(container.id) sys.exit(exit_code)
def run(self, project, options): """ Run a one-off command on a service. For example: $ fig run web python manage.py shell By default, linked services will be started, unless they are already running. If you do not want to start linked services, use `fig run --no-deps SERVICE COMMAND [ARGS...]`. Usage: run [options] [-e KEY=VAL...] SERVICE [COMMAND] [ARGS...] Options: --allow-insecure-ssl Allow insecure connections to the docker registry -d Detached mode: Run container in the background, print new container name. --entrypoint CMD Override the entrypoint of the image. -e KEY=VAL Set an environment variable (can be used multiple times) --no-deps Don't start linked services. --rm Remove container after run. Ignored in detached mode. -T Disable pseudo-tty allocation. By default `fig run` allocates a TTY. """ service = project.get_service(options['SERVICE']) insecure_registry = options['--allow-insecure-ssl'] if not options['--no-deps']: deps = service.get_linked_names() if len(deps) > 0: project.up( service_names=deps, start_links=True, recreate=False, insecure_registry=insecure_registry, ) tty = True if options['-d'] or options['-T'] or not sys.stdin.isatty(): tty = False if options['COMMAND']: command = [options['COMMAND']] + options['ARGS'] else: command = service.options.get('command') container_options = { 'command': command, 'tty': tty, 'stdin_open': not options['-d'], } if options['-e']: for option in options['-e']: if 'environment' not in service.options: service.options['environment'] = {} k, v = option.split('=', 1) service.options['environment'][k] = v if options['--entrypoint']: container_options['entrypoint'] = options.get('--entrypoint') container = service.create_container( one_off=True, insecure_registry=insecure_registry, **container_options ) if options['-d']: service.start_container(container, ports=None, one_off=True) print(container.name) else: service.start_container(container, ports=None, one_off=True) dockerpty.start(project.client, container.id, interactive=not options['-T']) exit_code = container.wait() if options['--rm']: log.info("Removing %s..." % container.name) project.client.remove_container(container.id) sys.exit(exit_code)
def runContainer(self, client): self.container_config = self.config.getContainerConfig() container_args = {} container_config = {} host_config = {} network_config = {} if self.container_config.get("command") is not None: if isinstance(self.container_config["command"], list): container_args["command"] = [ "bash", "-c", "${HOME}/pre_run.sh && exec", " ".join(self.container_config["command"]) ] else: container_args["command"] = [ "bash", "-c", "${HOME}/pre_run.sh && exec", self.container_config["command"] ] if self.container_config.get("entrypoint") is not None: container_args["entrypoint"] = self.container_config.get( "entrypoint") if self.container_config.get("workingDir") is not None: container_args["working_dir"] = self.container_config.get( "workingDir") if self.container_config.get("shm_size") is not None: host_config["shm_size"] = self.container_config.get("shm_size") if self.container_config.get("seccomp_profile") is not None: # This expects a file if (self.config.get("seccomp_dir")): if os.path.exists( os.path.join( self.config.get("seccomp_dir"), self.container_config.get("seccomp_profile"))): seccomp = open( os.path.join( self.config.get("seccomp_dir"), self.container_config.get("seccomp_profile"))) host_config["security_opt"] = [ "seccomp=" + " ".join(seccomp.read().splitlines()) ] elif os.path.exists(self.container_config.get("seccomp_profile")): seccomp = open(self.container_config.get("seccomp_profile")) host_config["security_opt"] = [ "seccomp=" + " ".join(seccomp.read().splitlines()) ] else: # Bail since we don't want to run a container that expects a security profile but can't find one! print("Seccomp profile not found: %s / %s - Aborting!" % (self.config.get("seccomp_dir"), self.container_config.get("seccomp_profile"))) sys.exit(1) container_args["image"] = self.container_config[ "image"] + ":" + self.container_config.get("tag", "latest") container_args["ports"] = [ key for key in self.container_config.get("ports") or [] ] container_args["detach"] = False if self.container_config.get("tty") == True: container_args["tty"] = True if self.container_config.get("workdir"): container_args["working_dir"] = self.container_config.get( "workdir") if self.container_config.get("stdin_open") == True: container_args["stdin_open"] = True # This requires docker-py as per PR #2465 from Ryan Leary # This also allows Vulkan to run in a user namespace, otherwise X tends to crash. if self.container_config.get("gpu_hook") is not None: if self.container_config["gpu_hook"].get("enabled") is True: host_config["device_requests"] = [ docker.types.DeviceRequest(count=-1, capabilities=[['gpu']]) ] print("self.container_config[environment] is %s" % self.container_config["environment"]) print("self.environment is %s" % self.environment) container_args["environment"] = { **self.container_config["environment"], **self.environment } if container_args.get("name") is not None: container_args["name"] = self.container_config["name"] elif self.container_config.get("name"): container_args["name"] = self.container_config.get("name") elif self.config.get("subprofileUser"): container_args["name"] = self.container_config["image"].replace( '/', '-') + "-" + self.config.safe_get("subprofileUser") else: container_args["name"] = self.container_config["image"].replace( '/', '-') + "-" + self.config.safe_get("profileUser") container_args["hostname"] = container_args["name"] host_config["auto_remove"] = True host_config["port_bindings"] = self.container_config.get("ports") host_config["binds"] = self.mounts host_config["devices"] = self.devices networking_config = {} if self.config.get("container", "network_mode") == "host": host_config["network_mode"] = "host" elif self.config.get("container", "network_mode") == "none": host_config["network_mode"] = "none" else: if self.config.get("container", "network") is not None and self.config.get( "devices", "network", "enabled") is True: networking_config = client.create_networking_config({ self.config.get("container", "network", "name"): client.create_endpoint_config() }) print("Container args is %s" % container_args) print("Building container") # This is gross, FIXME if networking_config: container = client.create_container( **container_args, host_config=client.create_host_config(**host_config), networking_config=networking_config) else: container = client.create_container( **container_args, host_config=client.create_host_config(**host_config)) # if self.config.get("container", "network") is not None and self.config.get("devices", "network", "enabled") is True: # network_config["net_id"] = self.config.get("container", "network", "name") # client.connect_container_to_network(container=container.get('Id'), **network_config) self.injectConfigs(client, container) print("Running container with entrypoint %s: " % container_args["entrypoint"]) client.start(container=container.get('Id')) # Check for the process if self.config.getAppConfig().get( "running_executable" ) is not None and not self.container_config.get("stdin_open"): while (True): print("Waiting on the process %s to run post_run script..." % self.config.getAppConfig().get("running_executable")) try: subprocess.check_output([ "pgrep", self.config.getAppConfig().get("running_executable") ]) print("Found process, running script.") break except Exception as e: print("Still waiting... %s" % e) time.sleep(5) continue print("Running post_run script") post_run_exec = client.exec_create( container=container.get('Id'), cmd=["/bin/bash", "-c", "${HOME}/post_run.sh"]) exec_start = client.exec_start(exec_id=post_run_exec, stream=True) for msg in exec_start: print(msg) if container_args.get("stdin_open"): print("Entering interactive mode.") dockerpty.start(client, container=container.get('Id')) client.wait(container=container.get('Id'))