Example #1
0
// Run executes a validated remote execution against a pod.
func (p *AttachOptions) Run() error {
	if p.Pod == nil {
		pod, err := p.Client.Pods(p.Namespace).Get(p.PodName)
		if err != nil {
			return err
		}
		if pod.Status.Phase != api.PodRunning {
			return fmt.Errorf("pod %s is not running and cannot be attached to; current phase is %s", p.PodName, pod.Status.Phase)
		}
		p.Pod = pod
		// TODO: convert this to a clean "wait" behavior
	}
	pod := p.Pod

	// ensure we can recover the terminal while attached
	t := term.TTY{Parent: p.InterruptParent}

	// check for TTY
	tty := p.TTY
	containerToAttach := p.GetContainer(pod)
	if tty && !containerToAttach.TTY {
		tty = false
		fmt.Fprintf(p.Err, "Unable to use a TTY - container %s did not allocate one\n", containerToAttach.Name)
	}
	if p.Stdin {
		t.In = p.In
		if tty && !t.IsTerminal() {
			tty = false
			fmt.Fprintln(p.Err, "Unable to use a TTY - input is not a terminal or the right kind of file")
		}
	}
	t.Raw = tty

	fn := func() error {
		if tty {
			fmt.Fprintln(p.Out, "\nHit enter for command prompt")
		}
		// TODO: consider abstracting into a client invocation or client helper
		req := p.Client.RESTClient.Post().
			Resource("pods").
			Name(pod.Name).
			Namespace(pod.Namespace).
			SubResource("attach")
		req.VersionedParams(&api.PodAttachOptions{
			Container: containerToAttach.Name,
			Stdin:     p.In != nil,
			Stdout:    p.Out != nil,
			Stderr:    p.Err != nil,
			TTY:       tty,
		}, api.ParameterCodec)

		return p.Attach.Attach("POST", req.URL(), p.Config, p.In, p.Out, p.Err, tty)
	}

	if err := t.Safe(fn); err != nil {
		return err
	}

	if p.Stdin && tty && pod.Spec.RestartPolicy == api.RestartPolicyAlways {
		fmt.Fprintf(p.Out, "Session ended, resume using '%s %s -c %s -i -t' command when the pod is running\n", p.CommandName, pod.Name, containerToAttach.Name)
	}
	return nil
}