diff --git a/pkg/provider/aci.go b/pkg/provider/aci.go index 0776feb3..2a8391f2 100644 --- a/pkg/provider/aci.go +++ b/pkg/provider/aci.go @@ -577,9 +577,22 @@ func (p *ACIProvider) RunInContainer(ctx context.Context, namespace, name, conta return err } + termSize := api.TermSize{ + Width: 60, + Height: 120, + } + if attach.TTY() { + resize := attach.Resize() + select { + case termSize = <-resize: + break + case <-time.After(5 * time.Second): + break + } + } // Set default terminal size - cols := int32(60) - rows := int32(120) + cols := int32(termSize.Width) + rows := int32(termSize.Height) cmdParam := strings.Join(cmd, " ") req := azaciv2.ContainerExecRequest{ Command: &cmdParam, diff --git a/pkg/provider/aci_test.go b/pkg/provider/aci_test.go index e8e11008..7a8b0918 100644 --- a/pkg/provider/aci_test.go +++ b/pkg/provider/aci_test.go @@ -1996,3 +1996,49 @@ func TestCreatePodWithLifecycleHooks(t *testing.T) { err = provider.CreatePod(context.Background(), pod) assert.Error(t, err, "ACI does not support lifecycle hooks") } + +func TestRunInContainer(t *testing.T) { + podName := "pod-" + uuid.New().String() + podNamespace := "ns-" + uuid.New().String() + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + cols := 42 + rows := 43 + aciMocks := createNewACIMock() + aciMocks.MockExecuteContainerCommand = func(ctx context.Context, resourceGroup, cgName, containerName string, containerReq azaciv2.ContainerExecRequest) (*azaciv2.ContainerExecResponse, error) { + assert.Equal(t, int32(cols), *containerReq.TerminalSize.Cols, "terminal cols size mismatch") + assert.Equal(t, int32(rows), *containerReq.TerminalSize.Rows, "terminal rows size mismatch") + return nil, fmt.Errorf("this error workarounds the websocket connection") + } + + aciMocks.MockGetContainerGroupInfo = func(ctx context.Context, resourceGroup, namespace, name, nodeName string) (*azaciv2.ContainerGroup, error) { + cg := testsutil.CreateContainerGroupObj(podName, podNamespace, "Succeeded", + testsutil.CreateACIContainersListObj(runningState, "Initializing", testsutil.CgCreationTime.Add(time.Second*2), testsutil.CgCreationTime.Add(time.Second*3), true, true, true), "Succeeded") + return cg, nil + } + + pod := testsutil.CreatePodObj(podName, podNamespace) + pod.Spec.Containers[0].StartupProbe = &corev1.Probe{} + + provider, err := createTestProvider(aciMocks, NewMockConfigMapLister(mockCtrl), + NewMockSecretLister(mockCtrl), NewMockPodLister(mockCtrl), nil) + if err != nil { + t.Fatal("failed to create the test provider", err) + } + + termSize := make(chan api.TermSize) + defer close(termSize) + go func() { + termSize <- api.TermSize{ + Width: uint16(cols), + Height: uint16(rows), + } + }() + attachIO := NewMockAttachIO(mockCtrl) + attachIO.EXPECT().TTY().Return(true) + attachIO.EXPECT().Resize().Return(termSize) + attachIO.EXPECT().Stdout().Return(nil) + + provider.RunInContainer(context.Background(), podNamespace, podName, "", nil, attachIO) +} diff --git a/pkg/provider/mock_vk_exec_test.go b/pkg/provider/mock_vk_exec_test.go new file mode 100644 index 00000000..21b5071d --- /dev/null +++ b/pkg/provider/mock_vk_exec_test.go @@ -0,0 +1,106 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/virtual-kubelet/virtual-kubelet/node/api (interfaces: AttachIO) + +// Package provider is a generated GoMock package. +package provider + +import ( + io "io" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + api "github.com/virtual-kubelet/virtual-kubelet/node/api" +) + +// MockAttachIO is a mock of AttachIO interface. +type MockAttachIO struct { + ctrl *gomock.Controller + recorder *MockAttachIOMockRecorder +} + +// MockAttachIOMockRecorder is the mock recorder for MockAttachIO. +type MockAttachIOMockRecorder struct { + mock *MockAttachIO +} + +// NewMockAttachIO creates a new mock instance. +func NewMockAttachIO(ctrl *gomock.Controller) *MockAttachIO { + mock := &MockAttachIO{ctrl: ctrl} + mock.recorder = &MockAttachIOMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockAttachIO) EXPECT() *MockAttachIOMockRecorder { + return m.recorder +} + +// Resize mocks base method. +func (m *MockAttachIO) Resize() <-chan api.TermSize { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Resize") + ret0, _ := ret[0].(<-chan api.TermSize) + return ret0 +} + +// Resize indicates an expected call of Resize. +func (mr *MockAttachIOMockRecorder) Resize() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Resize", reflect.TypeOf((*MockAttachIO)(nil).Resize)) +} + +// Stderr mocks base method. +func (m *MockAttachIO) Stderr() io.WriteCloser { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Stderr") + ret0, _ := ret[0].(io.WriteCloser) + return ret0 +} + +// Stderr indicates an expected call of Stderr. +func (mr *MockAttachIOMockRecorder) Stderr() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stderr", reflect.TypeOf((*MockAttachIO)(nil).Stderr)) +} + +// Stdin mocks base method. +func (m *MockAttachIO) Stdin() io.Reader { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Stdin") + ret0, _ := ret[0].(io.Reader) + return ret0 +} + +// Stdin indicates an expected call of Stdin. +func (mr *MockAttachIOMockRecorder) Stdin() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stdin", reflect.TypeOf((*MockAttachIO)(nil).Stdin)) +} + +// Stdout mocks base method. +func (m *MockAttachIO) Stdout() io.WriteCloser { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Stdout") + ret0, _ := ret[0].(io.WriteCloser) + return ret0 +} + +// Stdout indicates an expected call of Stdout. +func (mr *MockAttachIOMockRecorder) Stdout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stdout", reflect.TypeOf((*MockAttachIO)(nil).Stdout)) +} + +// TTY mocks base method. +func (m *MockAttachIO) TTY() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TTY") + ret0, _ := ret[0].(bool) + return ret0 +} + +// TTY indicates an expected call of TTY. +func (mr *MockAttachIOMockRecorder) TTY() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TTY", reflect.TypeOf((*MockAttachIO)(nil).TTY)) +}