def up_command(_args: argparse.Namespace, _unknow_args: [str]): printer = StepPrinter() try: printer.start_step("Finding Docker Container") docker_manager = DockerManager() printer.end_step() if not docker_manager.connection_ok(): docker_manager.print_connection_err() return compose_path = ENVY_CONFIG.get_services_compose_path() if compose_path: printer.start_step("Starting Sidecar Services") ComposeManager(compose_path).up() printer.end_step() if not ENVY_STATE.get_container_id(): printer.start_step("Creating ENVy environment") docker_manager.create_container() create_directory_if_not_exists() printer.end_step() printer.start_step("Starting Container") container = docker_manager.ensure_container() container.ensure_running() printer.end_step() if ENVY_CONFIG.should_x_forward(): printer.start_step("Setting up X forwarding") if platform.system() == "Darwin": x_error = "WARNING: failed to set up X forwarding. X applications will likely fail. Is XQuartz installed and running?" else: x_error = "WARNING: failed to set up X forwarding. X applications will likely fail. Do you have an X server running?" if os.path.exists("/tmp/.X11-unix/X0"): try: subprocess.run(["xhost", "+", "localhost"], check=True, capture_output=True) except subprocess.SubprocessError: print(x_error) else: print(x_error) printer.end_step() step_builder = Builder(container, printer) step_builder.build() except ContainerError as err: printer.error(err.code)
def create_container(self) -> ContainerManager: """ Creates an ENVy container. Requires that the container does not already exist, and that the image already exists. Raises: ContainerExists: The container ID specified in ENVY_STATE already exists. Returns: ContainerManager -- A container manager for the newly created container """ if self.get_container(): raise ContainerExists() image = ENVY_CONFIG.get_base_image() if ":" not in image: image += ":latest" try: self.docker_client.images.get(image) except docker.errors.ImageNotFound: print("Pulling base image, this may take a while...") self.docker_client.images.pull(image) container_manager = ContainerManager.create(self.docker_client, image) ENVY_STATE.set_container_id(container_manager.container_id) return container_manager
def down_command(_args: argparse.Namespace, _unknown_args: [str]): printer = StepPrinter() try: printer.start_step("Connecting to Docker") docker_manager = DockerManager() printer.end_step() if not docker_manager.connection_ok(): docker_manager.print_connection_err() return printer.start_step("Finding Docker Container") container = docker_manager.get_container() printer.end_step() if container: printer.start_step("Stopping Docker Container") container.ensure_stopped() printer.end_step() compose_path = ENVY_CONFIG.get_services_compose_path() if compose_path: printer.start_step("Stopping Sidecar Services") ComposeManager(compose_path).down() printer.end_step() except ContainerError as err: printer.error(err.code)
def main(): parser = get_parser(ENVY_CONFIG.get_actions()) args, unknown = parser.parse_known_args() if args.subparser_name: args.func(args, unknown) else: parser.print_help()
def __create_steps(self): for m in ENVY_CONFIG.get_setup_steps(): # Create step name = m["name"] label = m["label"] if m["type"] == "script": step = ScriptSetupStep( name, label, self.container, m["run"], m["as_user"] ) elif m["type"] == "remote": step = RemoteSetupStep(name, label, self.container, m["url"]) # Create and register triggers if m["triggers"] == "always": trigger = triggers.TriggerAlways() else: trigger_list = [] for t in m["triggers"]["system-packages"]: trigger_list.append( triggers.TriggerSystemPackage(t, self.system_package_step) ) for t in m["triggers"]["files"]: trigger_list.append(triggers.TriggerWatchfile(t)) for t in m["triggers"]["steps"]: trigger_list.append(triggers.TriggerStep(self.steps[t])) trigger = triggers.TriggerGroup(trigger_list) step.set_trigger(trigger) # Add step to dict self.steps[name] = step
def create(docker_client: DockerClient, image_id: str) -> "ContainerManager": """ Creates a container with the given image id Arguments: docker_client {DockerClient} -- A docker client image_id {str} -- the ID of the image to use Returns: ContainerManager -- a container manager for the created container """ print("Creating ENVy container") environment = {} mounts = [ Mount( ENVY_CONFIG.get_project_mount_path(), str(ENVY_PROJECT_DIR), type="bind", ), Mount("/var/run/docker.sock", "/var/run/docker.sock", type="bind"), ] if ENVY_CONFIG.should_x_forward(): mounts += [Mount("/tmp/.X11-unix", "/tmp/.X11-unix", type="bind")] if platform.system() == "Darwin": environment["DISPLAY"] = "host.docker.internal:0" else: environment["DISPLAY"] = ":0" container = docker_client.containers.create( image_id, "tail -f /dev/null", name=ContainerManager.__generate_container_name(), network=ENVY_CONFIG.get_network(), network_mode=ENVY_CONFIG.get_network_mode(), ports=ENVY_CONFIG.get_ports(), mounts=mounts, environment=environment, ) return ContainerManager(docker_client, container.id)
def exec(self, command: str, as_user: bool = False, relpath: str = None): """ Executes the command in the container Arguments: command {str} -- The command to run. Usually /bin/bash <> relpath {str} -- Relative path to project root to enter before executing. Optional, defaults to none. Raises: ContainerNotFound: The container was not found ContainerNotRunning: The container was not running """ if not self.is_running(): raise ContainerNotRunning() cdto = ENVY_CONFIG.get_project_mount_path() if relpath is not None: cdto = Path(ENVY_CONFIG.get_project_mount_path(), relpath) command_inside_project = "/bin/bash -c 'cd {}; {}'".format( cdto, command.replace("'", "'\\''")) if as_user: groups = ",".join(str(x) for x in os.getgroups()) userspec = str(os.getuid()) + ":" + str(os.getgid()) command_inside_project = "/usr/sbin/chroot --groups={} --userspec={} / /bin/bash -c 'export HOME=/uhome; cd {}; {}'".format( groups, userspec, ENVY_CONFIG.get_project_mount_path(), command.replace("'", "'\\''"), ) exit_code = dockerpty.exec_command(self.docker_client, self.container_id, command_inside_project) if exit_code != 0: raise ContainerError(exit_code)
def nuke_command(_args: argparse.Namespace, _unknown_args: [str]): printer = StepPrinter() try: printer.start_step("Destroying ENVy Environment") docker_manager = DockerManager() if not docker_manager.connection_ok(): docker_manager.print_connection_err() return docker_manager.nuke() ENVY_STATE.nuke() compose_path = ENVY_CONFIG.get_services_compose_path() if compose_path: ComposeManager(compose_path).nuke() printer.end_step() except ContainerError as err: printer.error(err.code)
def __create_system_packages_step(self): self.system_package_step = AptPackageManagerStep( self.container, ENVY_CONFIG.get_system_packages() ) self.steps[self.system_package_step.name] = self.system_package_step