def test_get_healthcheck_for_instance_cmd(self):
     fake_service = "fake_service"
     fake_namespace = "fake_namespace"
     fake_hostname = "fake_hostname"
     fake_random_port = 666
     fake_cmd = "/bin/fake_command"
     fake_service_config = long_running_service_tools.LongRunningServiceConfig(
         service=fake_service,
         cluster="fake_cluster",
         instance=fake_namespace,
         config_dict={"healthcheck_mode": "cmd", "healthcheck_cmd": fake_cmd},
         branch_dict={},
     )
     fake_service_namespace_config = long_running_service_tools.ServiceNamespaceConfig({})
     with contextlib.nested(
         mock.patch(
             "paasta_tools.long_running_service_tools.load_service_namespace_config",
             autospec=True,
             return_value=fake_service_namespace_config,
         ),
         mock.patch("socket.getfqdn", autospec=True, return_value=fake_hostname),
     ) as (load_service_namespace_config_patch, hostname_patch):
         expected = ("cmd", fake_cmd)
         actual = long_running_service_tools.get_healthcheck_for_instance(
             fake_service, fake_namespace, fake_service_config, fake_random_port
         )
         assert expected == actual
 def test_get_healthcheck_for_instance_custom_soadir(self):
     fake_service = "fake_service"
     fake_namespace = "fake_namespace"
     fake_hostname = "fake_hostname"
     fake_random_port = 666
     fake_soadir = "/fake/soadir"
     fake_service_config = long_running_service_tools.LongRunningServiceConfig(
         service=fake_service,
         cluster="fake_cluster",
         instance=fake_namespace,
         config_dict={"healthcheck_mode": None},
         branch_dict={},
     )
     fake_service_namespace_config = long_running_service_tools.ServiceNamespaceConfig({})
     with contextlib.nested(
         mock.patch(
             "paasta_tools.long_running_service_tools.load_service_namespace_config",
             autospec=True,
             return_value=fake_service_namespace_config,
         ),
         mock.patch("socket.getfqdn", autospec=True, return_value=fake_hostname),
     ) as (load_service_namespace_config_patch, hostname_patch):
         expected = (None, None)
         actual = long_running_service_tools.get_healthcheck_for_instance(
             fake_service, fake_namespace, fake_service_config, fake_random_port, soa_dir=fake_soadir
         )
         assert expected == actual
         load_service_namespace_config_patch.assert_called_once_with(fake_service, fake_namespace, fake_soadir)
    def test_get_healthcheck_for_instance_http(self):
        fake_service = "fake_service"
        fake_namespace = "fake_namespace"
        fake_hostname = "fake_hostname"
        fake_random_port = 666

        fake_path = "/fake_path"
        fake_service_config = long_running_service_tools.LongRunningServiceConfig(
            service=fake_service, cluster="fake_cluster", instance=fake_namespace, config_dict={}, branch_dict={}
        )
        fake_service_namespace_config = long_running_service_tools.ServiceNamespaceConfig(
            {"mode": "http", "healthcheck_uri": fake_path}
        )
        with contextlib.nested(
            mock.patch(
                "paasta_tools.long_running_service_tools.load_service_namespace_config",
                autospec=True,
                return_value=fake_service_namespace_config,
            ),
            mock.patch("socket.getfqdn", autospec=True, return_value=fake_hostname),
        ) as (load_service_namespace_config_patch, hostname_patch):
            expected = ("http", "http://%s:%d%s" % (fake_hostname, fake_random_port, fake_path))
            actual = long_running_service_tools.get_healthcheck_for_instance(
                fake_service, fake_namespace, fake_service_config, fake_random_port
            )
            assert expected == actual
    def test_get_healthcheck_for_instance_tcp(self):
        fake_service = 'fake_service'
        fake_namespace = 'fake_namespace'
        fake_hostname = 'fake_hostname'
        fake_random_port = 666

        fake_service_config = long_running_service_tools.LongRunningServiceConfig(
            service=fake_service,
            cluster='fake_cluster',
            instance=fake_namespace,
            config_dict={},
            branch_dict={},
        )
        fake_service_namespace_config = long_running_service_tools.ServiceNamespaceConfig(
            {
                'mode': 'tcp',
            })
        with mock.patch(
                'paasta_tools.long_running_service_tools.load_service_namespace_config',
                autospec=True,
                return_value=fake_service_namespace_config,
        ), mock.patch(
                'socket.getfqdn',
                autospec=True,
                return_value=fake_hostname,
        ):
            expected = ('tcp',
                        'tcp://%s:%d' % (fake_hostname, fake_random_port))
            actual = long_running_service_tools.get_healthcheck_for_instance(
                fake_service,
                fake_namespace,
                fake_service_config,
                fake_random_port,
            )
            assert expected == actual
    def test_get_healthcheck_for_instance_tcp(self):
        fake_service = 'fake_service'
        fake_namespace = 'fake_namespace'
        fake_hostname = 'fake_hostname'
        fake_random_port = 666

        fake_service_config = long_running_service_tools.LongRunningServiceConfig(
            service=fake_service,
            cluster='fake_cluster',
            instance=fake_namespace,
            config_dict={},
            branch_dict={},
        )
        fake_service_namespace_config = long_running_service_tools.ServiceNamespaceConfig({
            'mode': 'tcp',
        })
        with contextlib.nested(
            mock.patch('paasta_tools.long_running_service_tools.load_service_namespace_config',
                       autospec=True,
                       return_value=fake_service_namespace_config),
            mock.patch('socket.getfqdn', autospec=True, return_value=fake_hostname),
        ) as (
            load_service_namespace_config_patch,
            hostname_patch
        ):
            expected = ('tcp', 'tcp://%s:%d' % (fake_hostname, fake_random_port))
            actual = long_running_service_tools.get_healthcheck_for_instance(
                fake_service, fake_namespace, fake_service_config, fake_random_port)
            assert expected == actual
Beispiel #6
0
    def test_get_healthcheck_for_instance_http(self):
        fake_service = 'fake_service'
        fake_namespace = 'fake_namespace'
        fake_hostname = 'fake_hostname'
        fake_random_port = 666

        fake_path = '/fake_path'
        fake_service_config = long_running_service_tools.LongRunningServiceConfig(
            service=fake_service,
            cluster='fake_cluster',
            instance=fake_namespace,
            config_dict={},
            branch_dict={},
        )
        fake_service_namespace_config = long_running_service_tools.ServiceNamespaceConfig({
            'mode': 'http',
            'healthcheck_uri': fake_path,
        })
        with contextlib.nested(
            mock.patch('paasta_tools.long_running_service_tools.load_service_namespace_config',
                       autospec=True,
                       return_value=fake_service_namespace_config),
            mock.patch('socket.getfqdn', autospec=True, return_value=fake_hostname),
        ) as (
            load_service_namespace_config_patch,
            hostname_patch
        ):
            expected = ('http', 'http://%s:%d%s' % (fake_hostname, fake_random_port, fake_path))
            actual = long_running_service_tools.get_healthcheck_for_instance(
                fake_service, fake_namespace, fake_service_config, fake_random_port)
            assert expected == actual
Beispiel #7
0
 def test_get_healthcheck_for_instance_custom_soadir(self):
     fake_service = 'fake_service'
     fake_namespace = 'fake_namespace'
     fake_hostname = 'fake_hostname'
     fake_random_port = 666
     fake_soadir = '/fake/soadir'
     fake_service_config = long_running_service_tools.LongRunningServiceConfig(
         service=fake_service,
         cluster='fake_cluster',
         instance=fake_namespace,
         config_dict={
             'healthcheck_mode': None,
         },
         branch_dict={},
     )
     fake_service_namespace_config = long_running_service_tools.ServiceNamespaceConfig({})
     with contextlib.nested(
         mock.patch('paasta_tools.long_running_service_tools.load_service_namespace_config',
                    autospec=True,
                    return_value=fake_service_namespace_config),
         mock.patch('socket.getfqdn', autospec=True, return_value=fake_hostname),
     ) as (
         load_service_namespace_config_patch,
         hostname_patch
     ):
         expected = (None, None)
         actual = long_running_service_tools.get_healthcheck_for_instance(
             fake_service, fake_namespace, fake_service_config, fake_random_port, soa_dir=fake_soadir)
         assert expected == actual
         load_service_namespace_config_patch.assert_called_once_with(fake_service, fake_namespace, fake_soadir)
Beispiel #8
0
 def test_get_healthcheck_for_instance_cmd(self):
     fake_service = 'fake_service'
     fake_namespace = 'fake_namespace'
     fake_hostname = 'fake_hostname'
     fake_random_port = 666
     fake_cmd = '/bin/fake_command'
     fake_service_config = long_running_service_tools.LongRunningServiceConfig(
         service=fake_service,
         cluster='fake_cluster',
         instance=fake_namespace,
         config_dict={
             'healthcheck_mode': 'cmd',
             'healthcheck_cmd': fake_cmd
         },
         branch_dict={},
     )
     fake_service_namespace_config = long_running_service_tools.ServiceNamespaceConfig({})
     with contextlib.nested(
         mock.patch('paasta_tools.long_running_service_tools.load_service_namespace_config',
                    autospec=True,
                    return_value=fake_service_namespace_config),
         mock.patch('socket.getfqdn', autospec=True, return_value=fake_hostname),
     ) as (
         load_service_namespace_config_patch,
         hostname_patch
     ):
         expected = ('cmd', fake_cmd)
         actual = long_running_service_tools.get_healthcheck_for_instance(
             fake_service, fake_namespace, fake_service_config, fake_random_port)
         assert expected == actual
Beispiel #9
0
    def test_get_healthcheck_for_instance_not_matching_mode(self):
        fake_service = "fake_service"
        fake_namespace = "fake_namespace"
        fake_hostname = "fake_hostname"
        fake_random_port = 666

        fake_service_config = long_running_service_tools.LongRunningServiceConfig(
            service=fake_service,
            cluster="fake_cluster",
            instance=fake_namespace,
            config_dict={},
            branch_dict=None,
        )
        fake_service_namespace_config = long_running_service_tools.ServiceNamespaceConfig(
            {"mode": "http"})
        with mock.patch(
                "paasta_tools.long_running_service_tools.load_service_namespace_config",
                autospec=True,
                return_value=fake_service_namespace_config,
        ), mock.patch("socket.getfqdn",
                      autospec=True,
                      return_value=fake_hostname):
            expected = ("http", "http://fake_hostname:666/status")
            actual = long_running_service_tools.get_healthcheck_for_instance(
                fake_service, fake_namespace, fake_service_config,
                fake_random_port)
            assert expected == actual
Beispiel #10
0
 def test_get_healthcheck_for_instance_custom_soadir(self):
     fake_service = "fake_service"
     fake_namespace = "fake_namespace"
     fake_hostname = "fake_hostname"
     fake_random_port = 666
     fake_soadir = "/fake/soadir"
     fake_service_config = long_running_service_tools.LongRunningServiceConfig(
         service=fake_service,
         cluster="fake_cluster",
         instance=fake_namespace,
         config_dict={"healthcheck_mode": None},
         branch_dict=None,
     )
     fake_service_namespace_config = long_running_service_tools.ServiceNamespaceConfig(
         {})
     with mock.patch(
             "paasta_tools.long_running_service_tools.load_service_namespace_config",
             autospec=True,
             return_value=fake_service_namespace_config,
     ) as load_service_namespace_config_patch, mock.patch(
             "socket.getfqdn", autospec=True, return_value=fake_hostname):
         expected = (None, None)
         actual = long_running_service_tools.get_healthcheck_for_instance(
             fake_service,
             fake_namespace,
             fake_service_config,
             fake_random_port,
             soa_dir=fake_soadir,
         )
         assert expected == actual
         load_service_namespace_config_patch.assert_called_once_with(
             fake_service, fake_namespace, fake_soadir)
Beispiel #11
0
 def test_get_healthcheck_for_instance_cmd(self):
     fake_service = "fake_service"
     fake_namespace = "fake_namespace"
     fake_hostname = "fake_hostname"
     fake_random_port = 666
     fake_cmd = "/bin/fake_command"
     fake_service_config = long_running_service_tools.LongRunningServiceConfig(
         service=fake_service,
         cluster="fake_cluster",
         instance=fake_namespace,
         config_dict={
             "instances": 1,
             "healthcheck_mode": "cmd",
             "healthcheck_cmd": fake_cmd,
         },
         branch_dict=None,
     )
     fake_service_namespace_config = long_running_service_tools.ServiceNamespaceConfig(
         {})
     with mock.patch(
             "paasta_tools.long_running_service_tools.load_service_namespace_config",
             autospec=True,
             return_value=fake_service_namespace_config,
     ), mock.patch("socket.getfqdn",
                   autospec=True,
                   return_value=fake_hostname):
         expected = ("cmd", fake_cmd)
         actual = long_running_service_tools.get_healthcheck_for_instance(
             fake_service, fake_namespace, fake_service_config,
             fake_random_port)
         assert expected == actual
Beispiel #12
0
def run_docker_container(
    docker_client,
    service,
    instance,
    docker_hash,
    volumes,
    interactive,
    command,
    healthcheck,
    healthcheck_only,
    user_port,
    instance_config,
    soa_dir=DEFAULT_SOA_DIR,
    dry_run=False,
    json_dict=False,
    framework=None,
):
    """docker-py has issues running a container with a TTY attached, so for
    consistency we execute 'docker run' directly in both interactive and
    non-interactive modes.

    In non-interactive mode when the run is complete, stop the container and
    remove it (with docker-py).
    """
    if user_port:
        if check_if_port_free(user_port):
            chosen_port = user_port
        else:
            paasta_print(
                PaastaColors.red(
                    "The chosen port is already in use!\n"
                    "Try specifying another one, or omit (--port|-o) and paasta will find a free one for you"
                ),
                file=sys.stderr,
            )
            sys.exit(1)
    else:
        chosen_port = pick_random_port()
    environment = instance_config.get_env_dictionary()
    local_run_environment = get_local_run_environment_vars(
        instance_config=instance_config,
        port0=chosen_port,
        framework=framework,
    )
    environment.update(local_run_environment)
    net = instance_config.get_net()
    memory = instance_config.get_mem()
    container_name = get_container_name()
    docker_params = instance_config.format_docker_parameters()

    try:
        container_port = instance_config.get_container_port()
    except AttributeError:
        container_port = None

    docker_run_args = dict(
        memory=memory,
        chosen_port=chosen_port,
        container_port=container_port,
        container_name=container_name,
        volumes=volumes,
        env=environment,
        interactive=interactive,
        docker_hash=docker_hash,
        command=command,
        net=net,
        docker_params=docker_params,
    )
    docker_run_cmd = get_docker_run_cmd(**docker_run_args)
    joined_docker_run_cmd = ' '.join(docker_run_cmd)
    healthcheck_mode, healthcheck_data = get_healthcheck_for_instance(
        service, instance, instance_config, chosen_port, soa_dir=soa_dir)

    if dry_run:
        if json_dict:
            paasta_print(json.dumps(docker_run_args))
        else:
            paasta_print(json.dumps(docker_run_cmd))
        return 0
    else:
        paasta_print('Running docker command:\n%s' % PaastaColors.grey(joined_docker_run_cmd))

    if interactive:
        # NOTE: This immediately replaces us with the docker run cmd. Docker
        # run knows how to clean up the running container in this situation.
        execlp('paasta_docker_wrapper', *docker_run_cmd)
        # For testing, when execlp is patched out and doesn't replace us, we
        # still want to bail out.
        return 0

    container_started = False
    container_id = None
    try:
        (returncode, output) = _run(docker_run_cmd)
        if returncode != 0:
            paasta_print(
                'Failure trying to start your container!'
                'Returncode: %d'
                'Output:'
                '%s'
                ''
                'Fix that problem and try again.'
                'http://y/paasta-troubleshooting'
                % (returncode, output),
                sep='\n',
            )
            # Container failed to start so no need to cleanup; just bail.
            sys.exit(1)
        container_started = True
        container_id = get_container_id(docker_client, container_name)
        paasta_print('Found our container running with CID %s' % container_id)

        # If the service has a healthcheck, simulate it
        if healthcheck_mode is not None:
            healthcheck_result = simulate_healthcheck_on_service(
                instance_config=instance_config,
                docker_client=docker_client,
                container_id=container_id,
                healthcheck_mode=healthcheck_mode,
                healthcheck_data=healthcheck_data,
                healthcheck_enabled=healthcheck,
            )

        def _output_stdout_and_exit_code():
            returncode = docker_client.inspect_container(container_id)['State']['ExitCode']
            paasta_print('Container exited: %d)' % returncode)
            paasta_print('Here is the stdout and stderr:\n\n')
            paasta_print(
                docker_client.attach(container_id, stderr=True, stream=False, logs=True)
            )

        if healthcheck_only:
            if container_started:
                _output_stdout_and_exit_code()
                _cleanup_container(docker_client, container_id)
            if healthcheck_mode is None:
                paasta_print('--healthcheck-only, but no healthcheck is defined for this instance!')
                sys.exit(1)
            elif healthcheck_result is True:
                sys.exit(0)
            else:
                sys.exit(1)

        running = docker_client.inspect_container(container_id)['State']['Running']
        if running:
            paasta_print('Your service is now running! Tailing stdout and stderr:')
            for line in docker_client.attach(container_id, stderr=True, stream=True, logs=True):
                paasta_print(line)
        else:
            _output_stdout_and_exit_code()
            returncode = 3

    except KeyboardInterrupt:
        returncode = 3

    # Cleanup if the container exits on its own or interrupted.
    if container_started:
        returncode = docker_client.inspect_container(container_id)['State']['ExitCode']
        _cleanup_container(docker_client, container_id)
    return returncode
Beispiel #13
0
def run_docker_container(
    docker_client,
    service,
    instance,
    docker_url,
    volumes,
    interactive,
    command,
    healthcheck,
    healthcheck_only,
    user_port,
    instance_config,
    secret_provider_name,
    soa_dir=DEFAULT_SOA_DIR,
    dry_run=False,
    json_dict=False,
    framework=None,
    secret_provider_kwargs={},
    skip_secrets=False,
):
    """docker-py has issues running a container with a TTY attached, so for
    consistency we execute 'docker run' directly in both interactive and
    non-interactive modes.

    In non-interactive mode when the run is complete, stop the container and
    remove it (with docker-py).
    """
    if user_port:
        if check_if_port_free(user_port):
            chosen_port = user_port
        else:
            paasta_print(
                PaastaColors.red(
                    "The chosen port is already in use!\n"
                    "Try specifying another one, or omit (--port|-o) and paasta will find a free one for you"
                ),
                file=sys.stderr,
            )
            sys.exit(1)
    else:
        chosen_port = pick_random_port(service)
    environment = instance_config.get_env_dictionary()
    if not skip_secrets:
        secret_environment = decrypt_secret_environment_variables(
            secret_provider_name=secret_provider_name,
            environment=environment,
            soa_dir=soa_dir,
            service_name=service,
            cluster_name=instance_config.cluster,
            secret_provider_kwargs=secret_provider_kwargs,
        )
        environment.update(secret_environment)
    local_run_environment = get_local_run_environment_vars(
        instance_config=instance_config, port0=chosen_port, framework=framework
    )
    environment.update(local_run_environment)
    net = instance_config.get_net()
    memory = instance_config.get_mem()
    container_name = get_container_name()
    docker_params = instance_config.format_docker_parameters()

    healthcheck_mode, healthcheck_data = get_healthcheck_for_instance(
        service, instance, instance_config, chosen_port, soa_dir=soa_dir
    )
    if healthcheck_mode is None:
        container_port = None
        interactive = True
    elif not user_port and not healthcheck and not healthcheck_only:
        container_port = None
    else:
        try:
            container_port = instance_config.get_container_port()
        except AttributeError:
            container_port = None

    simulate_healthcheck = (
        healthcheck_only or healthcheck
    ) and healthcheck_mode is not None

    docker_run_args = dict(
        memory=memory,
        chosen_port=chosen_port,
        container_port=container_port,
        container_name=container_name,
        volumes=volumes,
        env=environment,
        interactive=interactive,
        detach=simulate_healthcheck,
        docker_hash=docker_url,
        command=command,
        net=net,
        docker_params=docker_params,
    )
    docker_run_cmd = get_docker_run_cmd(**docker_run_args)
    joined_docker_run_cmd = " ".join(docker_run_cmd)

    if dry_run:
        if json_dict:
            paasta_print(json.dumps(docker_run_args))
        else:
            paasta_print(json.dumps(docker_run_cmd))
        return 0
    else:
        paasta_print(
            "Running docker command:\n%s" % PaastaColors.grey(joined_docker_run_cmd)
        )

    merged_env = {**os.environ, **environment}

    if interactive or not simulate_healthcheck:
        # NOTE: This immediately replaces us with the docker run cmd. Docker
        # run knows how to clean up the running container in this situation.
        wrapper_path = shutil.which("paasta_docker_wrapper")
        # To properly simulate mesos, we pop the PATH, which is not available to
        # The executor
        merged_env.pop("PATH")
        execlpe(wrapper_path, *docker_run_cmd, merged_env)
        # For testing, when execlpe is patched out and doesn't replace us, we
        # still want to bail out.
        return 0

    container_started = False
    container_id = None
    try:
        (returncode, output) = _run(docker_run_cmd, env=merged_env)
        if returncode != 0:
            paasta_print(
                "Failure trying to start your container!"
                "Returncode: %d"
                "Output:"
                "%s"
                ""
                "Fix that problem and try again."
                "http://y/paasta-troubleshooting" % (returncode, output),
                sep="\n",
            )
            # Container failed to start so no need to cleanup; just bail.
            sys.exit(1)
        container_started = True
        container_id = get_container_id(docker_client, container_name)
        paasta_print("Found our container running with CID %s" % container_id)

        if simulate_healthcheck:
            healthcheck_result = simulate_healthcheck_on_service(
                instance_config=instance_config,
                docker_client=docker_client,
                container_id=container_id,
                healthcheck_mode=healthcheck_mode,
                healthcheck_data=healthcheck_data,
                healthcheck_enabled=healthcheck,
            )

        def _output_exit_code():
            returncode = docker_client.inspect_container(container_id)["State"][
                "ExitCode"
            ]
            paasta_print(f"Container exited: {returncode})")

        if healthcheck_only:
            if container_started:
                _output_exit_code()
                _cleanup_container(docker_client, container_id)
            if healthcheck_mode is None:
                paasta_print(
                    "--healthcheck-only, but no healthcheck is defined for this instance!"
                )
                sys.exit(1)
            elif healthcheck_result is True:
                sys.exit(0)
            else:
                sys.exit(1)

        running = docker_client.inspect_container(container_id)["State"]["Running"]
        if running:
            paasta_print("Your service is now running! Tailing stdout and stderr:")
            for line in docker_client.attach(
                container_id, stderr=True, stream=True, logs=True
            ):
                paasta_print(line)
        else:
            _output_exit_code()
            returncode = 3

    except KeyboardInterrupt:
        returncode = 3

    # Cleanup if the container exits on its own or interrupted.
    if container_started:
        returncode = docker_client.inspect_container(container_id)["State"]["ExitCode"]
        _cleanup_container(docker_client, container_id)
    return returncode
Beispiel #14
0
def run_docker_container(docker_client,
                         service,
                         instance,
                         docker_hash,
                         volumes,
                         interactive,
                         command,
                         hostname,
                         healthcheck,
                         healthcheck_only,
                         instance_config,
                         soa_dir=DEFAULT_SOA_DIR,
                         dry_run=False,
                         json_dict=False):
    """docker-py has issues running a container with a TTY attached, so for
    consistency we execute 'docker run' directly in both interactive and
    non-interactive modes.

    In non-interactive mode when the run is complete, stop the container and
    remove it (with docker-py).
    """
    if interactive:
        sys.stderr.write(
            PaastaColors.yellow(
                "Warning! You're running a container in interactive mode.\n"
                "This is *NOT* how Mesos runs containers.\n"
                "To run the container exactly as Mesos does, omit the -I flag.\n\n"
            ))
    else:
        sys.stderr.write(
            PaastaColors.yellow(
                "You're running a container in non-interactive mode.\n"
                "This is how Mesos runs containers.\n"
                "Note that some programs behave differently when running with no\n"
                "tty attached (as your program is about to run).\n\n"))
    environment = instance_config.get_env_dictionary()
    net = instance_config.get_net()
    memory = instance_config.get_mem()
    random_port = pick_random_port()
    container_name = get_container_name()
    docker_params = instance_config.format_docker_parameters()
    docker_run_args = dict(
        memory=memory,
        random_port=random_port,
        container_name=container_name,
        volumes=volumes,
        env=environment,
        interactive=interactive,
        docker_hash=docker_hash,
        command=command,
        hostname=hostname,
        net=net,
        docker_params=docker_params,
    )
    docker_run_cmd = get_docker_run_cmd(**docker_run_args)
    joined_docker_run_cmd = ' '.join(docker_run_cmd)
    healthcheck_mode, healthcheck_data = get_healthcheck_for_instance(
        service, instance, instance_config, random_port, soa_dir=soa_dir)

    if dry_run:
        if json_dict:
            sys.stdout.write(json.dumps(docker_run_args) + '\n')
        else:
            sys.stdout.write(json.dumps(docker_run_cmd) + '\n')
        sys.exit(0)
    else:
        sys.stdout.write('Running docker command:\n%s\n' %
                         PaastaColors.grey(joined_docker_run_cmd))

    if interactive:
        # NOTE: This immediately replaces us with the docker run cmd. Docker
        # run knows how to clean up the running container in this situation.
        execlp('docker', *docker_run_cmd)
        # For testing, when execlp is patched out and doesn't replace us, we
        # still want to bail out.
        return

    container_started = False
    container_id = None
    try:
        (returncode, output) = _run(joined_docker_run_cmd)
        if returncode != 0:
            sys.stdout.write('Failure trying to start your container!\n'
                             'Returncode: %d\n'
                             'Output:\n'
                             '%s\n'
                             '\n'
                             'Fix that problem and try again.\n'
                             'http://y/paasta-troubleshooting\n' %
                             (returncode, output))
            # Container failed to start so no need to cleanup; just bail.
            sys.exit(1)
        container_started = True
        container_id = get_container_id(docker_client, container_name)
        sys.stdout.write('Found our container running with CID %s\n' %
                         container_id)

        # If the service has a healthcheck, simulate it
        if healthcheck_mode:
            status, _ = simulate_healthcheck_on_service(
                instance_config, docker_client, container_id, healthcheck_mode,
                healthcheck_data, healthcheck)
        else:
            status = True

        def _output_on_failure():
            sys.stdout.write(
                'Your service failed to start, here is the stdout and stderr\n'
            )
            sys.stdout.write(
                PaastaColors.grey(
                    docker_client.attach(container_id,
                                         stderr=True,
                                         stream=False,
                                         logs=True)))

        if healthcheck_only:
            sys.stdout.write(
                'Detected --healthcheck-only flag, exiting now.\n')
            if container_started:
                _cleanup_container(docker_client, container_id)
            if status:
                sys.exit(0)
            else:
                _output_on_failure()
                sys.exit(1)

        running = docker_client.inspect_container(
            container_id)['State']['Running']
        if running:
            sys.stdout.write(
                'Your service is now running! Tailing stdout and stderr:\n')
            for line in docker_client.attach(container_id,
                                             stderr=True,
                                             stream=True,
                                             logs=True):
                sys.stdout.write(PaastaColors.grey(line))
        else:
            _output_on_failure()
            returncode = 3

    except KeyboardInterrupt:
        returncode = 3

    # Cleanup if the container exits on its own or interrupted.
    if container_started:
        returncode = docker_client.inspect_container(
            container_id)['State']['ExitCode']
        _cleanup_container(docker_client, container_id)
    sys.exit(returncode)
Beispiel #15
0
def run_docker_container(
    docker_client,
    service,
    instance,
    docker_hash,
    volumes,
    interactive,
    command,
    hostname,
    healthcheck,
    healthcheck_only,
    instance_config,
    soa_dir=DEFAULT_SOA_DIR,
    dry_run=False,
    json_dict=False
):
    """docker-py has issues running a container with a TTY attached, so for
    consistency we execute 'docker run' directly in both interactive and
    non-interactive modes.

    In non-interactive mode when the run is complete, stop the container and
    remove it (with docker-py).
    """
    environment = instance_config.get_env_dictionary()
    net = instance_config.get_net()
    memory = instance_config.get_mem()
    random_port = pick_random_port()
    container_name = get_container_name()
    docker_params = instance_config.format_docker_parameters()
    docker_run_args = dict(
        memory=memory,
        random_port=random_port,
        container_name=container_name,
        volumes=volumes,
        env=environment,
        interactive=interactive,
        docker_hash=docker_hash,
        command=command,
        hostname=hostname,
        net=net,
        docker_params=docker_params,
    )
    docker_run_cmd = get_docker_run_cmd(**docker_run_args)
    joined_docker_run_cmd = ' '.join(docker_run_cmd)
    healthcheck_mode, healthcheck_data = get_healthcheck_for_instance(
        service, instance, instance_config, random_port, soa_dir=soa_dir)

    if dry_run:
        if json_dict:
            sys.stdout.write(json.dumps(docker_run_args) + '\n')
        else:
            sys.stdout.write(json.dumps(docker_run_cmd) + '\n')
        sys.exit(0)
    else:
        sys.stdout.write('Running docker command:\n%s\n' % PaastaColors.grey(joined_docker_run_cmd))

    if interactive:
        # NOTE: This immediately replaces us with the docker run cmd. Docker
        # run knows how to clean up the running container in this situation.
        execlp('docker', *docker_run_cmd)
        # For testing, when execlp is patched out and doesn't replace us, we
        # still want to bail out.
        return

    container_started = False
    container_id = None
    try:
        (returncode, output) = _run(joined_docker_run_cmd)
        if returncode != 0:
            sys.stdout.write(
                'Failure trying to start your container!\n'
                'Returncode: %d\n'
                'Output:\n'
                '%s\n'
                '\n'
                'Fix that problem and try again.\n'
                'http://y/paasta-troubleshooting\n'
                % (returncode, output)
            )
            # Container failed to start so no need to cleanup; just bail.
            sys.exit(1)
        container_started = True
        container_id = get_container_id(docker_client, container_name)
        sys.stdout.write('Found our container running with CID %s\n' % container_id)

        # If the service has a healthcheck, simulate it
        if healthcheck_mode is not None:
            healthcheck_result = simulate_healthcheck_on_service(
                instance_config=instance_config,
                docker_client=docker_client,
                container_id=container_id,
                healthcheck_mode=healthcheck_mode,
                healthcheck_data=healthcheck_data,
                healthcheck_enabled=healthcheck,
            )

        def _output_on_failure():
            returncode = docker_client.inspect_container(container_id)['State']['ExitCode']
            sys.stdout.write('Container exited: %d)' % returncode)
            sys.stdout.write('Here is the stdout and stderr:\n')
            sys.stdout.write(PaastaColors.grey(
                docker_client.attach(container_id, stderr=True, stream=False, logs=True)
            ))

        if healthcheck_only:
            if container_started:
                _cleanup_container(docker_client, container_id)
            if healthcheck_mode is None:
                sys.stdout.write('--healthcheck-only, but no healthcheck is defined for this instance!\n')
                sys.exit(1)
            elif healthcheck_result:
                sys.exit(0)
            else:
                _output_on_failure()
                sys.exit(1)

        running = docker_client.inspect_container(container_id)['State']['Running']
        if running:
            sys.stdout.write('Your service is now running! Tailing stdout and stderr:\n')
            for line in docker_client.attach(container_id, stderr=True, stream=True, logs=True):
                sys.stdout.write(PaastaColors.grey(line))
        else:
            _output_on_failure()
            returncode = 3

    except KeyboardInterrupt:
        returncode = 3

    # Cleanup if the container exits on its own or interrupted.
    if container_started:
        returncode = docker_client.inspect_container(container_id)['State']['ExitCode']
        _cleanup_container(docker_client, container_id)
    sys.exit(returncode)