Exemple #1
0
def main():
    """
    Top-level function for Telepresence
    """

    ########################################
    # Preliminaries: No changes to the machine or the cluster, no cleanup
    # Capture environment info and the user's intent

    # Check for a subcommand
    with crash_reporting():
        args = command_parse_args(None, only_for_commands=True)
    if args is not None:
        command_main(args)

    with crash_reporting():
        args = parse_args()  # tab-completion stuff goes here

        runner = Runner(Output(args.logfile), None, args.verbose)
        span = runner.span()
        runner.add_cleanup("Stop time tracking", span.end)
        runner.kubectl = KubeInfo(runner, args)

        start_proxy = proxy.setup(runner, args)
        do_connect = connect.setup(runner, args)
        get_remote_env, write_env_files = remote_env.setup(runner, args)
        launch = outbound.setup(runner, args)
        mount_remote = mount.setup(runner, args)

        final_checks(runner, args)

        # Usage tracking
        call_scout(runner, args)

    ########################################
    # Now it's okay to change things

    with runner.cleanup_handling(), crash_reporting(runner):
        # Set up the proxy pod (operation -> pod name)
        remote_info = start_proxy(runner)

        # Connect to the proxy (pod name -> ssh object)
        socks_port, ssh = do_connect(runner, remote_info)

        # Capture remote environment information (ssh object -> env info)
        env = get_remote_env(runner, remote_info)

        # Handle filesystem stuff
        mount_dir = mount_remote(runner, env, ssh)

        # Maybe write environment files
        write_env_files(runner, env)

        # Set up outbound networking (pod name, ssh object)
        # Launch user command with the correct environment (...)
        user_process = launch(
            runner, remote_info, env, socks_port, ssh, mount_dir
        )

        wait_for_exit(runner, user_process)
Exemple #2
0
def main():
    """
    Top-level function for Telepresence
    """

    with crash_reporting():
        ########################################
        # Preliminaries: No changes to the machine or the cluster, no cleanup
        # Capture environment info

        args = parse_args()  # tab-completion stuff goes here

        runner = Runner(args.logfile, args.verbose)
        span = runner.span()
        runner.add_cleanup("Stop time tracking", span.end)
        set_kube_command(runner, args)

    with runner.cleanup_handling(), crash_reporting(runner):
        ########################################
        # Intent: Fast, user prompts here, cleanup available
        # Capture the user's intent

        start_proxy = proxy.setup(runner, args)
        do_connect = connect.setup(runner, args)
        get_remote_env, write_env_files = remote_env.setup(runner, args)
        launch = outbound.setup(runner, args)
        mount_remote = mount.setup(runner, args)

        final_checks(runner, args)

        # Usage tracking
        call_scout(runner, args)

        ########################################
        # Action: Perform the user's intended operation(s)
        # Now it's okay to change things

        # Set up the proxy pod (operation -> pod name)
        remote_info = start_proxy(runner)

        # Connect to the proxy (pod name -> ssh object)
        socks_port, ssh = do_connect(runner, remote_info)

        # Capture remote environment information (ssh object -> env info)
        env, pod_info = get_remote_env(runner, ssh, remote_info)

        # Handle filesystem stuff
        mount_dir = mount_remote(runner, env, ssh)

        # Maybe write environment files
        write_env_files(runner, env)

        # Set up outbound networking (pod name, ssh object)
        # Launch user command with the correct environment (...)
        user_process = launch(
            runner, remote_info, env, socks_port, ssh, mount_dir, pod_info
        )

        runner.wait_for_exit(user_process)
Exemple #3
0
def proxy(config: typing.Dict[str, typing.Any]) -> None:
    """Start sshuttle proxy to Kubernetes."""
    cidrs = config["cidrs"]
    expose_ports = config["expose_ports"]
    to_pod = config["to_pod"]
    from_pod = config["from_pod"]
    exclude_proxy = config["exclude_proxy"]

    # Launch local sshd so Tel outside can forward 38023 to the cluster
    runner = Runner("-", False)
    runner.check_call(["/usr/sbin/sshd", "-e"])

    # Wait for the cluster to be available
    ssh = SSH(runner, 38023, "[email protected]")
    if not ssh.wait():
        raise RuntimeError(
            "SSH from local container to the cluster failed to start.")

    # Figure out IP addresses to exclude, from the incoming ssh
    exclusions = []
    netstat_output = runner.get_output(["netstat", "-n"])
    for line in netstat_output.splitlines():
        if not line.startswith("tcp") or "ESTABLISHED" not in line:
            continue
        parts = line.split()
        try:
            for address in (parts[3], parts[4]):
                ip, port = address.split(":")
                exclusions.extend(["-x", ip])
        except (IndexError, ValueError):
            runner.write("Failed on line: " + line)
            raise
    assert exclusions, netstat_output

    if exclude_proxy:
        for cidr in exclude_proxy:
            exclusions.extend(["-x", cidr])

    # Start the sshuttle VPN-like thing:
    sshuttle_cmd = get_sshuttle_command(ssh, "nat") + exclusions + cidrs
    main_process = Popen(sshuttle_cmd, universal_newlines=True)

    # Start the SSH tunnels to expose local services:
    expose_local_services(runner, ssh, expose_ports, to_pod, from_pod)

    # Wait for everything to exit:
    runner.wait_for_exit(main_process)
Exemple #4
0
def proxy(config: dict):
    """Start sshuttle proxy to Kubernetes."""
    cidrs = config["cidrs"]
    expose_ports = config["expose_ports"]

    # Launch local sshd so Tel outside can forward 38023 to the cluster
    runner = Runner("-", "-", False)
    runner.check_call(["/usr/sbin/sshd", "-e"])

    # Wait for the cluster to be available
    ssh = SSH(runner, 38023, "[email protected]")
    ssh.wait()

    # Figure out IP addresses to exclude, from the incoming ssh
    exclusions = []
    netstat_output = runner.get_output(["netstat", "-n"])
    for line in netstat_output.splitlines():
        if not line.startswith("tcp") or "ESTABLISHED" not in line:
            continue
        parts = line.split()
        try:
            for address in (parts[3], parts[4]):
                ip, port = address.split(":")
                exclusions.extend(["-x", ip])
        except (IndexError, ValueError):
            runner.write("Failed on line: " + line)
            raise
    assert exclusions, netstat_output

    # Start the sshuttle VPN-like thing:
    # XXX duplicates code in telepresence, remove duplication
    main_process = Popen([
        "sshuttle-telepresence", "-v", "--dns", "--method", "nat", "-e", (
            "ssh -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null " +
            "-F /dev/null"
        ), "-r",
        "[email protected]:38023"
    ] + exclusions + cidrs)

    # Start the SSH tunnels to expose local services:
    expose_local_services(runner, ssh, expose_ports)

    # Wait for everything to exit:
    runner.wait_for_exit(main_process)
Exemple #5
0
def command_main(args):
    """
    Top-level function for Telepresence when executing subcommands
    """

    with crash_reporting():
        runner = Runner(Output(args.logfile), None, args.verbose)
        span = runner.span()
        runner.add_cleanup("Stop time tracking", span.end)
        runner.kubectl = KubeInfo(runner, args)

        args.operation = args.command
        args.method = "teleproxy"
        call_scout(runner, args)

    if args.command == "outbound":
        return outbound.command(runner)

    raise runner.fail("Not implemented!")
Exemple #6
0
def analyze_args(session):
    """Construct session info based on user arguments"""
    args = session.args
    output = session.output
    kube_info = KubeInfo(args)

    session.output.write(
        "Context: {}, namespace: {}, kubectl_command: {}\n".format(
            kube_info.context, kube_info.namespace, kube_info.command))

    # Figure out if we need capability that allows for ports < 1024:
    if any([p < 1024 for p in args.expose.remote()]):
        if kube_info.command == "oc":
            # OpenShift doesn't support running as root:
            raise SystemExit("OpenShift does not support ports <1024.")
        args.needs_root = True
    else:
        args.needs_root = False

    runner = Runner(output, kube_info, args.verbose)

    # minikube/minishift break DNS because DNS gets captured, sent to
    # minikube, which sends it back to DNS server set by host, resulting in
    # loop... we've fixed that for most cases, but not --deployment.
    def check_if_in_local_vm() -> bool:
        # Minikube just has 'minikube' as context'
        if args.context == "minikube":
            return True
        # Minishift has complex context name, so check by server:
        if runner.kubectl.command == "oc" and which("minishift"):
            ip = runner.get_output(["minishift", "ip"]).strip()
            if ip and ip in kube_info.server:
                return True
        return False

    args.in_local_vm = check_if_in_local_vm()
    if args.in_local_vm:
        output.write("Looks like we're in a local VM, e.g. minikube.\n")
    if (args.in_local_vm and args.method == "vpn-tcp"
            and args.new_deployment is None and args.swap_deployment is None):
        raise runner.fail(
            "vpn-tcp method doesn't work with minikube/minishift when"
            " using --deployment. Use --swap-deployment or"
            " --new-deployment instead.")

    # Make sure we can access Kubernetes:
    try:
        runner.get_output(
            runner.kubectl("get", "pods", "telepresence-connectivity-check",
                           "--ignore-not-found"),
            stderr=STDOUT,
        )
    except (CalledProcessError, OSError, IOError) as exc:
        sys.stderr.write("Error accessing Kubernetes: {}\n".format(exc))
        if exc.output:
            sys.stderr.write("{}\n".format(exc.output.strip()))
        raise runner.fail("Cluster access failed")

    # Make sure we can run openssh:
    try:
        version = runner.get_output(["ssh", "-V"],
                                    stdin=DEVNULL,
                                    stderr=STDOUT)
        if not version.startswith("OpenSSH"):
            raise runner.fail("'ssh' is not the OpenSSH client, apparently.")
    except (CalledProcessError, OSError, IOError) as e:
        raise runner.fail("Error running ssh: {}\n".format(e))

    # Other requirements:
    require_command(runner, "torsocks",
                    "Please install torsocks (v2.1 or later)")
    if args.mount:
        require_command(runner, "sshfs")

    # Need conntrack for sshuttle on Linux:
    if sys.platform.startswith("linux") and args.method == "vpn-tcp":
        require_command(runner, "conntrack")

    return kube_info, runner