Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add conpty (pseudo console) package #1228

Merged
merged 4 commits into from
Dec 15, 2021
Merged

Conversation

dcantah
Copy link
Contributor

@dcantah dcantah commented Nov 16, 2021

This change adds a conpty package (and necessary bindings) that houses go friendly wrappers around
the Pseudo Console API in Windows. This will be used to support tty scenarios for Host Process containers.

There's not many tests I can add here as you need to hook this up to a running
process, where that work is coming soon. I've included a video of this working below using the
new process execution package I've been working on.

conpty.mp4

Code for the demo for a sneak peak at the API:

package main

import (
	"context"
	"fmt"
	"io"
	"log"
	"os"
	"syscall"

	"github.com/Microsoft/hcsshim/internal/conpty"
	"github.com/Microsoft/hcsshim/internal/exec"
	"github.com/Microsoft/hcsshim/internal/jobobject"
	"github.com/containerd/console"
)

type rawConReader struct {
	f *os.File
}

func (r rawConReader) Read(b []byte) (int, error) {
	n, err := syscall.Read(syscall.Handle(r.f.Fd()), b)
	if n == 0 && len(b) != 0 && err == nil {
		// A zero-byte read on a console indicates that the user wrote Ctrl-Z.
		b[0] = 26
		return 1, nil
	}
	return n, err
}

func main() {
	cpty, err := conpty.New(80, 20, 0)
	if err != nil {
		log.Fatal(err)
	}
	defer cpty.Close()

	job, err := jobobject.Create(context.Background(), &jobobject.Options{Name: "test"})
	if err != nil {
		log.Fatal(err)
	}
	defer job.Close()

	e, err := exec.New(
		`C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe`,
		"powershell",
		exec.WithJobObject(job),
		exec.WithConPty(cpty),
		exec.WithDir("C:\\"),
		exec.WithEnv(os.Environ()),
	)
	if err != nil {
		log.Fatal(err)
	}

	err = e.Start()
	if err != nil {
		log.Fatalf("failed to start process: %v", err)
	}

	var osStdin io.Reader = os.Stdin
	con, err := console.ConsoleFromFile(os.Stdin)
	if err == nil {
		err = con.SetRaw()
		if err != nil {
			log.Fatal(err)
		}
		defer func() {
			_ = con.Reset()
		}()
		// Console reads return EOF whenever the user presses Ctrl-Z.
		// Wrap the reads to translate these EOFs back.
		osStdin = rawConReader{os.Stdin}
	}

	go func() {
		_, _ = io.Copy(os.Stdout, cpty.OutPipe())
	}()

	go func() {
		_, _ = io.Copy(cpty.InPipe(), osStdin)
	}()

	err = e.Wait()
	if err != nil {
		log.Fatalf("error waiting for process: %v", err)
	}
	fmt.Printf("exit code was: %d\n", e.ExitCode())
}

@dcantah dcantah requested a review from a team as a code owner November 16, 2021 05:00
@dcantah dcantah force-pushed the conpty branch 2 times, most recently from 1738766 to 1d2b761 Compare November 16, 2021 05:13
@dcantah
Copy link
Contributor Author

dcantah commented Nov 16, 2021

fyi @jsturtevant @marosset

internal/conpty/conpty.go Outdated Show resolved Hide resolved
This change adds a conpty package that houses go friendly wrappers around
the Pseudo Console API in Windows. This will be used to support tty scenarios
for Host Process containers.

There's not many tests I can add here as you need to hook this up to a running
process, where that work is coming.

Signed-off-by: Daniel Canter <dcanter@microsoft.com>
* CPty -> ConPTY
* Unexport InitializeProcThreadAttributeList

Signed-off-by: Daniel Canter <dcanter@microsoft.com>
Signed-off-by: Daniel Canter <dcanter@microsoft.com>
The issue with x/sys/windows is being solved here
https://go-review.googlesource.com/c/sys/+/371276/1/windows/exec_windows.go#153.
This change adds a comment to state that we'll swap once the fix is in.

Signed-off-by: Daniel Canter <dcanter@microsoft.com>
Copy link
Contributor

@anmaxvl anmaxvl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

small nit, otherwise LGTM

internal/winapi/process.go Show resolved Hide resolved
internal/winapi/zsyscall_windows.go Show resolved Hide resolved
@dcantah dcantah merged commit f8cbd0b into microsoft:master Dec 15, 2021
dcantah added a commit to dcantah/hcsshim that referenced this pull request Jan 4, 2022
* Add conpty (pseudo console) package

This change adds a conpty package that houses go friendly wrappers around
the Pseudo Console API in Windows. This will be used to support tty scenarios
for Host Process containers.

There's not many tests I can add here as you need to hook this up to a running
process, where that work is coming.

Signed-off-by: Daniel Canter <dcanter@microsoft.com>
(cherry picked from commit f8cbd0b)
Signed-off-by: Daniel Canter <dcanter@microsoft.com>
dcantah added a commit to dcantah/hcsshim that referenced this pull request Jan 4, 2022
* Add conpty (pseudo console) package

This change adds a conpty package that houses go friendly wrappers around
the Pseudo Console API in Windows. This will be used to support tty scenarios
for Host Process containers.

There's not many tests I can add here as you need to hook this up to a running
process, where that work is coming.

Signed-off-by: Daniel Canter <dcanter@microsoft.com>
(cherry picked from commit f8cbd0b)
Signed-off-by: Daniel Canter <dcanter@microsoft.com>
princepereira pushed a commit to princepereira/hcsshim that referenced this pull request Aug 29, 2024
* Add conpty (pseudo console) package

This change adds a conpty package that houses go friendly wrappers around
the Pseudo Console API in Windows. This will be used to support tty scenarios
for Host Process containers.

There's not many tests I can add here as you need to hook this up to a running
process, where that work is coming.

Signed-off-by: Daniel Canter <dcanter@microsoft.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants