Set initial console size based on process spec

Signed-off-by: Will Martin <wmartin@pivotal.io>
Signed-off-by: Petar Petrov <pppepito86@gmail.com>
Signed-off-by: Ed King <eking@pivotal.io>
Signed-off-by: Roberto Jimenez Sanchez <jszroberto@gmail.com>
Signed-off-by: Thomas Godkin <tgodkin@pivotal.io>
This commit is contained in:
Konstantinos Karampogias 2017-09-26 15:39:46 +02:00 committed by CF Garden
parent 0351df1c5a
commit 605dc5c811
5 changed files with 87 additions and 3 deletions

View File

@ -522,6 +522,8 @@ func (c *linuxContainer) newInitConfig(process *Process) *initConfig {
cfg.Rlimits = process.Rlimits
}
cfg.CreateConsole = process.ConsoleSocket != nil
cfg.ConsoleWidth = process.ConsoleWidth
cfg.ConsoleHeight = process.ConsoleHeight
return cfg
}

View File

@ -62,6 +62,8 @@ type initConfig struct {
ContainerId string `json:"containerid"`
Rlimits []configs.Rlimit `json:"rlimits"`
CreateConsole bool `json:"create_console"`
ConsoleWidth uint16 `json:"console_width"`
ConsoleHeight uint16 `json:"console_height"`
Rootless bool `json:"rootless"`
}
@ -171,12 +173,25 @@ func setupConsole(socket *os.File, config *initConfig, mount bool) error {
// however, that setupUser (specifically fixStdioPermissions) *will* change
// the UID owner of the console to be the user the process will run as (so
// they can actually control their console).
console, slavePath, err := console.NewPty()
pty, slavePath, err := console.NewPty()
if err != nil {
return err
}
if config.ConsoleHeight != 0 && config.ConsoleWidth != 0 {
err = pty.Resize(console.WinSize{
Height: config.ConsoleHeight,
Width: config.ConsoleWidth,
})
if err != nil {
return err
}
}
// After we return from here, we don't need the console anymore.
defer console.Close()
defer pty.Close()
// Mount the console inside our rootfs.
if mount {
@ -185,7 +200,7 @@ func setupConsole(socket *os.File, config *initConfig, mount bool) error {
}
}
// While we can access console.master, using the API is a good idea.
if err := utils.SendFd(socket, console.Name(), console.Fd()); err != nil {
if err := utils.SendFd(socket, pty.Name(), pty.Fd()); err != nil {
return err
}
// Now, dup over all the things.

View File

@ -47,6 +47,10 @@ type Process struct {
// ExtraFiles specifies additional open files to be inherited by the container
ExtraFiles []*os.File
// Initial sizings for the console
ConsoleWidth uint16
ConsoleHeight uint16
// Capabilities specify the capabilities to keep when executing the process inside the container
// All capabilities not specified will be dropped from the processes capability mask
Capabilities *configs.Capabilities

View File

@ -116,3 +116,60 @@ function teardown() {
[[ ${lines[0]} =~ 1000 ]]
[[ ${lines[1]} =~ 5 ]]
}
@test "runc exec [tty consolesize]" {
# allow writing to filesystem
sed -i 's/"readonly": true/"readonly": false/' config.json
# run busybox detached
runc run -d --console-socket $CONSOLE_SOCKET test_busybox
[ "$status" -eq 0 ]
# make sure we're running
testcontainer test_busybox running
tty_info_with_consize_size=$( cat <<EOF
{
"terminal": true,
"consoleSize": {
"height": 10,
"width": 110
},
"args": [
"/bin/sh",
"-c",
"/bin/stty -a > /tmp/tty-info"
],
"cwd": "/"
}
EOF
)
# run the exec
runc exec --pid-file pid.txt -d --console-socket $CONSOLE_SOCKET -p <( echo $tty_info_with_consize_size ) test_busybox
[ "$status" -eq 0 ]
# check the pid was generated
[ -e pid.txt ]
#wait user process to finish
timeout 1 tail --pid=$(head -n 1 pid.txt) -f /dev/null
tty_info=$( cat <<EOF
{
"args": [
"/bin/cat",
"/tmp/tty-info"
],
"cwd": "/"
}
EOF
)
# run the exec
runc exec -p <( echo $tty_info ) test_busybox
[ "$status" -eq 0 ]
# test tty width and height against original process.json
[[ ${lines[0]} =~ "rows 10; columns 110" ]]
}

View File

@ -108,6 +108,12 @@ func newProcess(p specs.Process) (*libcontainer.Process, error) {
NoNewPrivileges: &p.NoNewPrivileges,
AppArmorProfile: p.ApparmorProfile,
}
if p.ConsoleSize != nil {
lp.ConsoleWidth = uint16(p.ConsoleSize.Width)
lp.ConsoleHeight = uint16(p.ConsoleSize.Height)
}
if p.Capabilities != nil {
lp.Capabilities = &configs.Capabilities{}
lp.Capabilities.Bounding = p.Capabilities.Bounding