def destroy():
    """
    Kill and remove a container.
    """

    destroy = recv_proto(Destroy)

    # Acquire a lock for this container
    with container_lock(destroy.container_id.value):

        logger.info("Ensuring container %s is killed",
                    destroy.container_id.value)

        stdout, _, return_code = invoke_docker("kill",
                                               [destroy.container_id.value],
                                               stdout=PIPE)
        if return_code > 0:
            logger.error("Failed to kill container, bad exit code (%d)",
                         return_code)
            exit(1)

        logger.info("Removing container %s", destroy.container_id.value)

        stdout, _, return_code = invoke_docker("rm",
                                               [destroy.container_id.value],
                                               stdout=PIPE)
        if return_code > 0:
            logger.error("Failed to remove container, bad exit code (%d)",
                         return_code)
            exit(1)
示例#2
0
def containers():
    """
    List all running containers. Dumps out the containerizer.Containers proto
    which lists all of the container IDs.
    """

    stdout, _, exit_code = invoke_docker("ps", stdout=PIPE, stderr=PIPE)
    if exit_code > 0:
        logger.error("Docker returned a bad status code (%d)" % exit_code)
        exit(1)

    running_containers = Containers()

    stdout.readline() # Read off the header
    for line in stdout:
        container_id = line.rstrip().split(" ")[-1]

        if len(container_id) > 0:
            container = running_containers.containers.add()
            container.value = container_id
        else:
            logger.error("Failed to parse container id, empty")
            exit(1)

    send_proto(running_containers)
示例#3
0
def wait():
    """
    Wait for a running container to exit.
    """

    wait = recv_proto(Wait)

    # Acquire a lock for this container
    with container_lock(wait.container_id.value, "wait"):

        logger.info("Waiting for container %s", wait.container_id.value)

        stdout, _, return_code = invoke_docker("wait", [wait.container_id.value], stdout=PIPE)
        if return_code > 0:
            logger.error("Failed to wait for container, bad exit code (%d)", return_code)
            exit(1)

        container_exit = int(stdout.readline().rstrip())
        logger.info("Container exit code: %d", container_exit)

        termination = Termination()
        termination.killed = False
        termination.status = container_exit
        termination.message = ""

        send_proto(termination)
def destroy_container(container_id):

    logger.info("Ensuring container %s is killed", container_id.value)

    stdout, _, return_code = invoke_docker("kill", [container_id.value], stdout=PIPE)
    if return_code > 0:
        logger.error("Failed to kill container, bad exit code (%d)", return_code)
        return False

    logger.info("Removing container %s", container_id.value)

    stdout, _, return_code = invoke_docker("rm", [container_id.value], stdout=PIPE)
    if return_code > 0:
        logger.error("Failed to remove container, bad exit code (%d)", return_code)
        return False

    return True
def containers():
    """
    List all running containers. Dumps out the a Containers proto
    which lists all of the container IDs.
    """

    stdout, _, exit_code = invoke_docker("ps", stdout=PIPE, stderr=PIPE)
    if exit_code > 0:
        logger.error("Docker returned a bad status code (%d)" % exit_code)
        exit(1)

    send_proto(parse_docker_ps(stdout))
def launch():
    """
    Launch a new Mesos executor in a Docker container.
    """

    launch = recv_proto(Launch)

    # Acquire a lock for this container
    with container_lock(launch.container_id.value):

        logger.info("Preparing to launch container %s", launch.container_id.value)

        try:
            run_arguments = build_docker_args(launch)
        except Exception, e:
            logger.error("Caught exception: %s", e)
            raise  # Re-raise the exception

        logger.info("Launching docker container")
        _, _, return_code = invoke_docker("run", run_arguments)

        if return_code > 0:
            logger.error("Failed to launch container")
            exit(1)
示例#7
0
def launch():
    """
    Launch a new Mesos executor in a Docker container.
    """

    launch = recv_proto(Launch)

    # Acquire a lock for this container
    with container_lock(launch.container_id.value):

        logger.info("Preparing to launch container %s", launch.container_id.value)

        # Build up the docker arguments
        arguments = []

        # Set the container ID
        arguments.extend([
            "--name", launch.container_id.value
        ])

        # Configure the docker network to share the hosts
        arguments.extend([
            "--net", "host"
        ])

        # Configure the user
        if launch.HasField("user"):
            arguments.extend([
                "-u", launch.user
            ])

        # Figure out where the executor is
        if launch.HasField("executor_info"):
            executor = launch.executor_info.command.value
            uris = launch.executor_info.command.uris

            # Environment variables
            for env in launch.executor_info.command.environment.variables:
                arguments.extend([
                    "-e",
                    "%s=%s" % (env.name, env.value)
                ])
        else:
            logger.info("No executor given, launching with mesos-executor")
            executor = "%s/mesos-executor" % os.environ['MESOS_LIBEXEC_DIRECTORY']
            uris = launch.task_info.command.uris

            # Environment variables
            for env in launch.task_info.command.environment.variables:
                arguments.extend([
                    "-e",
                    "%s=%s" % (env.name, env.value)
                ])

        # Download the URIs
        logger.info("Fetching URIs")
        if fetch_uris(launch.directory, uris) > 0:
            logger.error("Mesos fetcher returned bad exit code")
            exit(1)

        # Link the mesos native library
        native_library = os.environ['MESOS_NATIVE_LIBRARY']
        arguments.extend(["-v", "%s:/usr/lib/%s" % (native_library, os.path.basename(native_library))])

        # Set the resource configuration
        cpu_shares = 0
        max_memory = 0
        ports = set()

        # Grab the resources from the task and executor
        resource_sets = [launch.task_info.resources,
                         launch.executor_info.resources]
        for resources in resource_sets:
            for resource in resources:
                if resource.name == "cpus":
                    cpu_shares += int(resource.scalar.value)
                if resource.name == "mem":
                    max_memory += int(resource.scalar.value)
                if resource.name == "ports":
                    for port_range in resource.ranges.range:
                        for port in xrange(port_range.begin, port_range.end + 1):
                            ports.add(port)

        if cpu_shares > 0:
            arguments.extend(["-c", str(cpu_shares * 256)])
        if max_memory > 0:
            arguments.extend(["-m", "%dm" % max_memory])
        if len(ports) > 0:
            for port in ports:
                arguments.extend(["-p", ":%i" % port])

        logger.info("Configured with executor %s" % executor)

        # Add the sandbox directory
        arguments.extend(["-v", "%s:/mesos-sandbox" % (launch.directory)])
        arguments.extend(["-w", "/mesos-sandbox"])

        # Set the MESOS_DIRECTORY environment variable to the sandbox mount point
        arguments.extend(["-e", "MESOS_DIRECTORY=/mesos-sandbox"])

        # Pass through the rest of the mesos environment variables
        mesos_env = ["MESOS_FRAMEWORK_ID", "MESOS_EXECUTOR_ID",
                     "MESOS_SLAVE_ID", "MESOS_CHECKPOINT",
                     "MESOS_SLAVE_PID", "MESOS_RECOVERY_TIMEOUT",
                     "MESOS_NATIVE_LIBRARY"]
        for key in mesos_env:
            if key in os.environ:
                arguments.extend(["-e", "%s=%s" % (key, os.environ[key])])

        # Parse the container image
        image = None
        extra_args = []
        if launch.HasField("executor_info"):
            image = launch.executor_info.command.container.image
            for option in launch.executor_info.command.container.options:
                extra_args.append(option.split(" "))
        else:
            image = launch.task_info.command.container.image
            for option in launch.task_info.command.container.options:
                extra_args.append(option.split(" "))

        if not image:
            image = os.environ["MESOS_DEFAULT_CONTAINER_IMAGE"]
        if not image:
            logger.error("No default container image")
            exit(1)

        url = urlparse(image)
        image = ""
        if url.netloc:
            image = url.netloc
        image += url.path

        # Pull the image
        logger.info("Pulling latest docker image: %s", image)
        _, _, return_code = invoke_docker("pull", [image])
        if return_code > 0:
            logger.error("Failed to pull image (%d)", return_code)
            exit(1)

        # TODO(tarnfeld): Locking

        run_arguments = [
            "-d",  # Enable daemon mode
            "--net=bridge"  # Bridge the network with the host
        ]

        run_arguments.extend(arguments)
        run_arguments.extend(extra_args)
        run_arguments.extend(["-e", "GLOG_v=5"])
        run_arguments.append(image)
        run_arguments.extend(["sh", "-c"])
        run_arguments.append(executor + " >> stdout 2>>stderr")

        logger.info("Launching docker container")
        _, _, return_code = invoke_docker("run", run_arguments)

        if return_code > 0:
            logger.error("Failed to launch container")
            exit(1)
def build_docker_args(launch):

    # Build up the docker arguments
    arguments = []

    # Set the container ID
    arguments.extend([
        "--name", launch.container_id.value
    ])

    container_info = None

    # Figure out where the executor is
    if launch.HasField("executor_info"):
        executor = launch.executor_info.command.value
        uris = launch.executor_info.command.uris

        # Environment variables
        for env in launch.executor_info.command.environment.variables:
            arguments.extend([
                "-e",
                "%s=%s" % (env.name, env.value)
            ])

        if launch.executor_info.HasField("container"):
            container_info = launch.executor_info.container
    else:
        logger.info("No executor given, launching with mesos-executor")
        executor = "%s/mesos-executor" % os.environ['MESOS_LIBEXEC_DIRECTORY']
        uris = launch.task_info.command.uris

        # Environment variables
        for env in launch.task_info.command.environment.variables:
            arguments.extend([
                "-e",
                "%s=%s" % (env.name, env.value)
            ])

    # Pull out the ContainerInfo from either the task or the executor
    if launch.executor_info.HasField("container"):
        container_info = launch.executor_info.container
    elif launch.task_info.HasField("container"):
        container_info = launch.task_info.container

    # Pull out DockerInfo if it's there
    docker_info = None
    if container_info and container_info.type == 1:  # ContainerInfo.Type.DOCKER
        docker_info = container_info.docker

    # Configure the docker network to share the hosts
    net = "host"
    if docker_info:
        if docker_info.network == 1:  # DockerInfo.Network.HOST
            pass
        elif docker_info.network == 2:  # DockerInfo.Network.BRIDGE
            net = "bridge"
        elif docker_info.network == 3:  # DockerInfo.Network.NONE
            net = "none"
        else:
            raise Exception("Unsupported docker network type")

    arguments.extend([
        "--net", "%s" % net.lower()
    ])

    # Configure the user
    if launch.HasField("user"):
        arguments.extend([
            "-u", launch.user
        ])

    # Download the URIs
    logger.info("Fetching URIs")
    if fetch_uris(launch.directory, uris) > 0:
        raise Exception("Mesos fetcher returned bad exit code")

    # Set the resource configuration
    cpu_shares = 0
    max_memory = 0
    ports = set()

    # Grab the resources from the task and executor
    resource_sets = [launch.task_info.resources,
                     launch.executor_info.resources]
    for resources in resource_sets:
        for resource in resources:
            if resource.name == "cpus":
                cpu_shares += float(resource.scalar.value)
            if resource.name == "mem":
                max_memory += int(resource.scalar.value)
            if resource.name == "ports":
                for port_range in resource.ranges.range:
                    for port in xrange(port_range.begin, port_range.end + 1):
                        ports.add(port)

    if cpu_shares > 0.0:
        arguments.extend(["-c", str(int(cpu_shares * 1024))])
    if max_memory > 0:
        arguments.extend(["-m", "%dm" % max_memory])
    if len(ports) > 0:
        for port in ports:
            arguments.extend(["-p", ":%i" % port])

    logger.info("Configured with executor %s" % executor)

    # Set the MESOS_DIRECTORY environment variable to the sandbox mount point
    arguments.extend(["-e", "MESOS_DIRECTORY=/mesos-sandbox"])

    # Pass through the rest of the mesos environment variables
    mesos_env = ["MESOS_FRAMEWORK_ID", "MESOS_EXECUTOR_ID",
                 "MESOS_SLAVE_ID", "MESOS_CHECKPOINT",
                 "MESOS_SLAVE_PID", "MESOS_RECOVERY_TIMEOUT",
                 "MESOS_NATIVE_LIBRARY"]
    for key in mesos_env:
        if key in os.environ:
            arguments.extend(["-e", "%s=%s" % (key, os.environ[key])])

    # Add the sandbox directory
    arguments.extend(["-v", "%s:/mesos-sandbox" % (launch.directory)])
    arguments.extend(["-w", "/mesos-sandbox"])

    # Populate the docker arguments with any volumes to be mounted
    if container_info:
        for volume in container_info.volumes:
            volume_args = volume.container_path
            if volume.HasField("host_path"):
                volume_args = "%s:%s" % (
                    volume.host_path,
                    volume.container_path
                )
            if volume.HasField("mode"):
                if not volume.HasField("host_path"):
                    raise Exception("Host path is required with mode")
                if volume.mode == Volume.Mode.RW:
                    volume_args += ":rw"
                elif volume.mode == Volume.Mode.RO:
                    volume_args += ":ro"
                else:
                    raise Exception("Unsupported volume mode")

            arguments.extend(["-v", volume_args])

    # Populate the docker arguments with any port mappings
    if docker_info:
        for port_mapping in docker_info.port_mappings:
            if port_mapping.host_port not in ports:
                raise Exception("Port %i not included in resources" % port_mapping.host_port)
            port_args = "%i:%i" % (
                port_mapping.host_port,
                port_mapping.container_port
            )

            if port_mapping.HasField("protocol"):
                port_args += "/%s" % (port_mapping.protocol.lower())

            arguments.extend(["-p", port_args])

        if docker_info.privileged:
            arguments.append('--privileged')

        if docker_info.parameters:
            for param in docker_info.parameters:
                if param.key:
                    arguments.append(param.key)
                if param.value:
                    arguments.append(param.value)

    extra_args = []
    if docker_info:
        image = docker_info.image
    else:
        image = None
        if launch.HasField("executor_info"):
            image = launch.executor_info.command.container.image
            for option in launch.executor_info.command.container.options:
                extra_args.extend(option.split(" "))
        else:
            image = launch.task_info.command.container.image
            for option in launch.task_info.command.container.options:
                extra_args.extend(option.split(" "))

    if not image:
        image = os.environ["MESOS_DEFAULT_CONTAINER_IMAGE"]
    if not image:
        raise Exception("No default container image")

    # Parse the container image
    url = urlparse(image)
    if url.netloc:
        docker_image = "%s/%s" % (url.netloc, url.path.lstrip("/"))
    else:
        docker_image = url.path

    # Pull the image
    logger.info("Pulling latest docker image: %s", docker_image)
    _, _, return_code = invoke_docker("pull", [docker_image])
    if return_code > 0:
        raise Exception("Failed to pull image (%d)", return_code)

    run_arguments = [
        "-d",  # Enable daemon mode
    ]

    run_arguments.extend(arguments)
    run_arguments.extend(extra_args)
    run_arguments.append(docker_image)
    run_arguments.extend(["sh", "-c"])
    run_arguments.append(executor + " >> /mesos-sandbox/docker_stdout 2>> /mesos-sandbox/docker_stderr")

    return run_arguments
def launch():
    """
    Launch a new Mesos executor in a Docker container.
    """

    launch = recv_proto(Launch)

    # Acquire a lock for this container
    with container_lock(launch.container_id.value):

        logger.info("Prepraring to launch container %s", launch.container_id.value)

        # Build up the docker arguments
        arguments = []

        # Set the container ID
        arguments.extend([
            "--name", launch.container_id.value
        ])

        # Configure the user
        if launch.HasField("user"):
            arguments.extend([
                "-u", launch.user
            ])

        # Figure out where the executor is
        if launch.HasField("executor_info"):
            executor = launch.executor_info.command.value
            uris = launch.executor_info.command.uris

            # Environment variables
            for env in launch.executor_info.command.environment.variables:
                arguments.extend([
                    "-e",
                    "%s=%s" % (env.name, env.value)
                ])
        else:
            logger.info("No executor given, launching with mesos-executor")
            executor = "%s/mesos-executor" % os.environ['MESOS_LIBEXEC_DIRECTORY']
            uris = launch.task_info.command.uris

            # Environment variables
            for env in launch.task_info.command.environment.variables:
                arguments.extend([
                    "-e",
                    "%s=%s" % (env.name, env.value)
                ])

        # Download the URIs
        logger.info("Fetching URIs")
        if fetch_uris(launch.directory, uris) > 0:
            logger.error("Mesos fetcher returned bad exit code")
            exit(1)

        # Link the mesos native library
        native_library = os.environ['MESOS_NATIVE_LIBRARY']
        arguments.extend(["-v", "%s:/usr/lib/%s" % (native_library, os.path.basename(native_library))])

        # Set the resource configuration
        for resource in launch.task_info.resources:
            if resource.name == "cpus":
                arguments.extend(["-c", str(int(resource.scalar.value * 256))])
            if resource.name == "mem":
                arguments.extend(["-m", "%dm" % (int(resource.scalar.value))])
            if resource.name == "ports":
                for port_range in resource.ranges.range:
                    for port in xrange(port_range.begin, port_range.end + 1):
                        arguments.extend(["-p", "%i:%i" % (port, port)])

        logger.info("Configured with executor %s" % executor)

        # Add the sandbox directory
        arguments.extend(["-v", "%s:/mesos-sandbox" % (launch.directory)])
        arguments.extend(["-w", "/mesos-sandbox"])

        # Set the MESOS_DIRECTORY environment variable to the sandbox mount point
        arguments.extend(["-e", "MESOS_DIRECTORY=/mesos-sandbox"])

        # Pass through the rest of the mesos environment variables
        mesos_env = ["MESOS_FRAMEWORK_ID", "MESOS_EXECUTOR_ID",
                     "MESOS_SLAVE_ID", "MESOS_CHECKPOINT",
                     "MESOS_SLAVE_PID", "MESOS_RECOVERY_TIMEOUT"]
        for key in mesos_env:
            if key in os.environ:
                arguments.extend(["-e", "%s=%s" % (key, os.environ[key])])

        # Parse the container image
        image = None
        extra_args = []
        if launch.task_info.HasField("executor"):
            image = launch.executor_info.command.container.image
            for option in launch.executor_info.command.container.options:
                extra_args.append(option.split(" "))
        else:
            image = launch.task_info.command.container.image
            for option in launch.task_info.command.container.options:
                extra_args.append(option.split(" "))

        if not image:
            image = os.environ["MESOS_DEFAULT_CONTAINER_IMAGE"]
        if not image:
            logger.error("No default container image")
            exit(1)

        url = urlparse(image)
        image = ""
        if url.netloc:
            image = url.netloc
        image += url.path


        # TODO(tarnfeld): Locking

        run_arguments = [
            "-d", # Enable daemon mode
            "--net=bridge" # Bridge the network with the host
        ]

        run_arguments.extend(arguments)
        run_arguments.extend(extra_args)
        run_arguments.extend(["-e", "GLOG_v=5"])
        run_arguments.append(image)
        run_arguments.extend(["sh", "-c"])
        run_arguments.append(executor + " >> stdout 2>>stderr")

        logger.info("Launching docker container")
        _, _, return_code = invoke_docker("run", run_arguments)

        if return_code > 0:
            logger.error("Failed to launch container")
            exit(1)