Skip to content
This repository has been archived by the owner on Jan 10, 2023. It is now read-only.

Allow attaching TTYs to containers #186

Merged
merged 1 commit into from
Oct 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion executor/mock/jobrunner.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ type JobInput struct {
CPU *int64
// StopTimeoutSeconds is the duration we wait after SIGTERM for the container to exit
KillWaitSeconds uint32
// Tty attaches a tty to the container via a passthrough attribute
Tty bool
}

// JobRunResponse returned from RunJob
Expand Down Expand Up @@ -201,14 +203,16 @@ func (jobRunner *JobRunner) StopExecutorAsync() {
}

// StartJob starts a job on an existing JobRunner and returns once the job is started
func (jobRunner *JobRunner) StartJob(jobInput *JobInput) *JobRunResponse {
func (jobRunner *JobRunner) StartJob(jobInput *JobInput) *JobRunResponse { // nolint: gocyclo
// Define some stock job to run
var jobID string

if jobInput.JobID == "" {
jobID = fmt.Sprintf("Titus-%v%v", r.Intn(1000), time.Now().Second())
} else {
jobID = jobInput.JobID
}

taskID := fmt.Sprintf("Titus-%v%v-Worker-0-2", r.Intn(1000), time.Now().Second())
env := map[string]string{
"TITUS_TASK_ID": taskID,
Expand Down Expand Up @@ -249,6 +253,9 @@ func (jobRunner *JobRunner) StartJob(jobInput *JobInput) *JobRunResponse {
if jobInput.Batch == "idle" {
ci.PassthroughAttributes["titusParameter.agent.batchPriority"] = "idle"
}
if jobInput.Tty {
ci.PassthroughAttributes["titusParameter.agent.ttyEnabled"] = "true"
}

if jobInput.KillWaitSeconds > 0 {
ci.KillWaitSeconds = protobuf.Uint32(jobInput.KillWaitSeconds)
Expand Down
28 changes: 28 additions & 0 deletions executor/mock/standalone/standalone_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ func TestStandalone(t *testing.T) {
testNoCPUBursting,
testCPUBursting,
testTwoCPUs,
testTty,
testTtyNegative,
}
for _, fun := range testFunctions {
fullName := runtime.FuncForPC(reflect.ValueOf(fun).Pointer()).Name()
Expand Down Expand Up @@ -847,3 +849,29 @@ func testTwoCPUs(t *testing.T, jobID string) {
t.Fail()
}
}

func testTty(t *testing.T, jobID string) {
ji := &mock.JobInput{
ImageName: ubuntu.name,
Version: ubuntu.tag,
EntrypointOld: `/usr/bin/tty`,
rgulewich marked this conversation as resolved.
Show resolved Hide resolved
JobID: jobID,
Tty: true,
}
if !mock.RunJobExpectingSuccess(ji) {
t.Fail()
}
}

func testTtyNegative(t *testing.T, jobID string) {
ji := &mock.JobInput{
ImageName: ubuntu.name,
Version: ubuntu.tag,
EntrypointOld: `/usr/bin/tty`,
JobID: jobID,
// Tty not specified
}
if !mock.RunJobExpectingFailure(ji) {
t.Fail()
}
}
6 changes: 6 additions & 0 deletions executor/runtime/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -407,13 +407,19 @@ func (r *DockerRuntime) dockerConfig(c *runtimeTypes.Container, binds []string,
return nil, nil, err
}

tty, err := c.GetTty()
if err != nil {
return nil, nil, err
}

containerCfg := &container.Config{
Image: c.QualifiedImageName(),
Entrypoint: entrypoint,
Cmd: cmd,
Labels: c.Labels,
Volumes: map[string]struct{}{},
Hostname: hostname,
Tty: tty,
}

useInit := true
Expand Down
15 changes: 15 additions & 0 deletions executor/runtime/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const (
// FuseEnabledParam is a container atttribute set to enable FUSE
FuseEnabledParam = "titusParameter.agent.fuseEnabled"
assignIPv6AddressParam = "titusParameter.agent.assignIPv6Address"
ttyEnabledParam = "titusParameter.agent.ttyEnabled"
)

// ErrMissingIAMRole indicates that the Titus job was submitted without an IAM role
Expand Down Expand Up @@ -279,6 +280,20 @@ func (c *Container) AssignIPv6Address() (bool, error) {
return val, nil
}

// GetTty should the container be assigned a tty?
func (c *Container) GetTty() (bool, error) {
ttyEnabledStr, ok := c.TitusInfo.GetPassthroughAttributes()[ttyEnabledParam]
if !ok {
return false, nil
}
val, err := strconv.ParseBool(ttyEnabledStr)
if err != nil {
return false, err
}

return val, nil
}

// Resources specify constraints to be applied to a Container
type Resources struct {
Mem int64 // in MiB
Expand Down
11 changes: 11 additions & 0 deletions executor/runtime/types/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,14 @@ func TestIPv6AddressAssignment(t *testing.T) {
assert.NoError(t, err)
assert.True(t, assignIPv6Address)
}

func TestTtyEnabled(t *testing.T) {
c := Container{
TitusInfo: &titus.ContainerInfo{
PassthroughAttributes: map[string]string{ttyEnabledParam: "true"},
},
}
tty, err := c.GetTty()
assert.NoError(t, err)
assert.True(t, tty)
}