From 56b96dbb1a0b35ccf42242a6d8fadf49138e0d2c Mon Sep 17 00:00:00 2001 From: Jan Dubois Date: Tue, 18 May 2021 11:18:19 -0700 Subject: [PATCH 1/4] Create pidfile and "bpm pid" command Some drain scripts send signals directly to the process via the PID from the pidfile (because bpm doesn't have a mechanism to send e.g. a USR1 signal). This obviously only works when the drain runs inside the same container as the process itself. This commit maintains a pid file at the /var/vcap/sys/run/bpm/$JOB/$PORC.pid location and also implements the `bpm pid` command to access it. Signed-off-by: Jan Dubois --- cmd/main.go | 2 ++ pkg/containerrun/bpm.go | 41 +++++++++++++++++++------------- pkg/containerrun/containerrun.go | 34 +++++++++++++++++++++----- 3 files changed, 55 insertions(+), 22 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index dd45fc9..54024ca 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,6 +1,7 @@ package main import ( + log "github.com/sirupsen/logrus" "os" cmd "code.cloudfoundry.org/quarks-container-run/cmd/containerrun" @@ -10,6 +11,7 @@ import ( func main() { pkg.WriteBPMscript() if err := cmd.NewDefaultContainerRunCmd().Execute(); err != nil { + log.Errorf("container-run failed: %v", err) os.Exit(1) } } diff --git a/pkg/containerrun/bpm.go b/pkg/containerrun/bpm.go index 90f6e7c..5db77b3 100644 --- a/pkg/containerrun/bpm.go +++ b/pkg/containerrun/bpm.go @@ -13,7 +13,7 @@ func WriteBPMscript() error { script := `#!/bin/bash function usage { - echo "usage: $0 [start|stop|quit|term|running] JOBNAME [-p PROCESSNAME]" + echo "usage: $0 [start|stop|quit|term|pid|running] JOBNAME [-p PROCESSNAME]" exit 1 } @@ -21,7 +21,7 @@ if [ $# != 2 -a $# != 4 ]; then usage fi if [ "$1" != "start" -a "$1" != "stop" -a "$1" != "running" -a \ - "$1" != "quit" -a "$1" != "term" ] + "$1" != "pid" -a "$1" != "quit" -a "$1" != "term" ] then usage fi @@ -37,6 +37,17 @@ if [ $# == 4 ]; then PROCESS="$4" fi +if [ "$CMD" == "pid" ]; then + PIDFILE="/var/vcap/sys/run/bpm/${JOB}/${PROCESS}.pid" + if [ -f "${PIDFILE}" ]; then + cat "${PIDFILE}"; echo + exit 0 + else + echo "Process is not running" + exit 1 + fi +fi + CONTAINER_RUN="/var/vcap/data/${JOB}/${PROCESS}_containerrun" if [ "$CMD" == "running" ]; then # Print yes/no if stdout is a tty @@ -47,20 +58,18 @@ if [ "$CMD" == "running" ]; then test -t 1 && echo "no" exit 1 fi -else - # "term" is the same as "stop", except we won't wait - ACTION="${CMD/term/stop}" - # Send "START", "STOP", or "QUIT" over UDP to the unix socket - # with a 1 seconds timeout to establish the connection. - echo "${ACTION^^}" | nc -w 1 -uU "${CONTAINER_RUN}.sock" - if [ "${CMD}" == "stop" ]; then - for i in $(seq 30); do - test ! -f "${CONTAINER_RUN}.running" && exit 0 - sleep 1 - done - echo Process did not stop within 30 seconds - exit 1 - fi +fi + +# "term" is the same as "stop", except we won't wait +ACTION="${CMD/term/stop}" +echo "${ACTION^^}" | nc -w 1 -uU "${CONTAINER_RUN}.sock" +if [ "${CMD}" == "stop" ]; then + for i in $(seq 30); do + test ! -f "${CONTAINER_RUN}.running" && exit 0 + sleep 1 + done + echo Process did not stop within 30 seconds + exit 1 fi ` if _, err := os.Stat(fileName); !os.IsNotExist(err) { diff --git a/pkg/containerrun/containerrun.go b/pkg/containerrun/containerrun.go index 45f17f4..76afe27 100644 --- a/pkg/containerrun/containerrun.go +++ b/pkg/containerrun/containerrun.go @@ -12,6 +12,8 @@ import ( "os" "os/exec" "os/signal" + "path/filepath" + "strconv" "strings" "sync" "syscall" @@ -347,20 +349,33 @@ func startMainProcess( processRegistry.Register(process) sentinel := fmt.Sprintf("/var/vcap/data/%s/%s_containerrun.running", jobName, processName) - file, _ := os.Create(sentinel) - _ = file.Close() + err = ioutil.WriteFile(sentinel, nil, 0755) + if err != nil { + return err + } + pidfile := fmt.Sprintf("/var/vcap/sys/run/bpm/%s/%s.pid", jobName, processName) + err = os.MkdirAll(filepath.Dir(pidfile), 0755) + if err != nil { + return err + } + err = ioutil.WriteFile(pidfile, []byte(strconv.Itoa(process.Pid())), 0755) + if err != nil { + return err + } go func() { if err := process.Wait(); err != nil { log.Debugf("Process has failed with error: %s\n", err) processRegistry.Unregister(process) - os.Remove(sentinel) + _ = os.Remove(sentinel) + _ = os.Remove(pidfile) errors <- &runErr{err} return } log.Debugln("Process has ended normally") processRegistry.Unregister(process) - os.Remove(sentinel) + _ = os.Remove(sentinel) + _ = os.Remove(pidfile) done <- struct{}{} }() @@ -468,7 +483,7 @@ func (cr *ContainerRunner) run( if err := cmd.Start(); err != nil { return nil, fmt.Errorf("failed to run command: %v", err) } - return NewContainerProcess(cmd.Process), nil + return NewContainerProcess(cmd.Process, cmd.Process.Pid), nil } // ConditionRunner satisfies the Runner interface. It represents a runner for a post-start @@ -521,6 +536,7 @@ func (cr *ConditionRunner) RunContext( // Process is the interface that wraps the Signal and Wait methods of a process. type Process interface { + Pid() int Signal(os.Signal) error Wait() error } @@ -534,12 +550,14 @@ type OSProcess interface { // ContainerProcess satisfies the Process interface. type ContainerProcess struct { process OSProcess + pid int } // NewContainerProcess constructs a new ContainerProcess. -func NewContainerProcess(process OSProcess) *ContainerProcess { +func NewContainerProcess(process OSProcess, pid int) *ContainerProcess { return &ContainerProcess{ process: process, + pid: pid, } } @@ -567,6 +585,10 @@ func (p *ContainerProcess) Wait() error { return nil } +func (p *ContainerProcess) Pid() int { + return p.pid +} + // Stdio represents the STDOUT and STDERR to be used by a process. type Stdio struct { Out io.Writer From 48da065e0c628b7c07a2b9e14806205a0338b315 Mon Sep 17 00:00:00 2001 From: Jan Dubois Date: Tue, 18 May 2021 11:49:12 -0700 Subject: [PATCH 2/4] Regenerate mocks because of interface changes Signed-off-by: Jan Dubois --- pkg/containerrun/mocks/mock_containerrun.go | 119 +++++++++++--------- pkg/containerrun/mocks/mock_context.go | 27 ++--- 2 files changed, 81 insertions(+), 65 deletions(-) diff --git a/pkg/containerrun/mocks/mock_containerrun.go b/pkg/containerrun/mocks/mock_containerrun.go index b57956f..55fc957 100644 --- a/pkg/containerrun/mocks/mock_containerrun.go +++ b/pkg/containerrun/mocks/mock_containerrun.go @@ -5,39 +5,40 @@ package mocks import ( - containerrun "code.cloudfoundry.org/quarks-container-run/pkg/containerrun" context "context" - gomock "github.com/golang/mock/gomock" net "net" os "os" exec "os/exec" reflect "reflect" + + containerrun "code.cloudfoundry.org/quarks-container-run/pkg/containerrun" + gomock "github.com/golang/mock/gomock" ) -// MockRunner is a mock of Runner interface +// MockRunner is a mock of Runner interface. type MockRunner struct { ctrl *gomock.Controller recorder *MockRunnerMockRecorder } -// MockRunnerMockRecorder is the mock recorder for MockRunner +// MockRunnerMockRecorder is the mock recorder for MockRunner. type MockRunnerMockRecorder struct { mock *MockRunner } -// NewMockRunner creates a new mock instance +// NewMockRunner creates a new mock instance. func NewMockRunner(ctrl *gomock.Controller) *MockRunner { mock := &MockRunner{ctrl: ctrl} mock.recorder = &MockRunnerMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockRunner) EXPECT() *MockRunnerMockRecorder { return m.recorder } -// Run mocks base method +// Run mocks base method. func (m *MockRunner) Run(arg0 containerrun.Command, arg1 containerrun.Stdio) (containerrun.Process, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Run", arg0, arg1) @@ -46,13 +47,13 @@ func (m *MockRunner) Run(arg0 containerrun.Command, arg1 containerrun.Stdio) (co return ret0, ret1 } -// Run indicates an expected call of Run +// Run indicates an expected call of Run. func (mr *MockRunnerMockRecorder) Run(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*MockRunner)(nil).Run), arg0, arg1) } -// RunContext mocks base method +// RunContext mocks base method. func (m *MockRunner) RunContext(arg0 context.Context, arg1 containerrun.Command, arg2 containerrun.Stdio) (containerrun.Process, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "RunContext", arg0, arg1, arg2) @@ -61,36 +62,36 @@ func (m *MockRunner) RunContext(arg0 context.Context, arg1 containerrun.Command, return ret0, ret1 } -// RunContext indicates an expected call of RunContext +// RunContext indicates an expected call of RunContext. func (mr *MockRunnerMockRecorder) RunContext(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RunContext", reflect.TypeOf((*MockRunner)(nil).RunContext), arg0, arg1, arg2) } -// MockChecker is a mock of Checker interface +// MockChecker is a mock of Checker interface. type MockChecker struct { ctrl *gomock.Controller recorder *MockCheckerMockRecorder } -// MockCheckerMockRecorder is the mock recorder for MockChecker +// MockCheckerMockRecorder is the mock recorder for MockChecker. type MockCheckerMockRecorder struct { mock *MockChecker } -// NewMockChecker creates a new mock instance +// NewMockChecker creates a new mock instance. func NewMockChecker(ctrl *gomock.Controller) *MockChecker { mock := &MockChecker{ctrl: ctrl} mock.recorder = &MockCheckerMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockChecker) EXPECT() *MockCheckerMockRecorder { return m.recorder } -// Check mocks base method +// Check mocks base method. func (m *MockChecker) Check(arg0 string) bool { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Check", arg0) @@ -98,36 +99,50 @@ func (m *MockChecker) Check(arg0 string) bool { return ret0 } -// Check indicates an expected call of Check +// Check indicates an expected call of Check. func (mr *MockCheckerMockRecorder) Check(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Check", reflect.TypeOf((*MockChecker)(nil).Check), arg0) } -// MockProcess is a mock of Process interface +// MockProcess is a mock of Process interface. type MockProcess struct { ctrl *gomock.Controller recorder *MockProcessMockRecorder } -// MockProcessMockRecorder is the mock recorder for MockProcess +// MockProcessMockRecorder is the mock recorder for MockProcess. type MockProcessMockRecorder struct { mock *MockProcess } -// NewMockProcess creates a new mock instance +// NewMockProcess creates a new mock instance. func NewMockProcess(ctrl *gomock.Controller) *MockProcess { mock := &MockProcess{ctrl: ctrl} mock.recorder = &MockProcessMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockProcess) EXPECT() *MockProcessMockRecorder { return m.recorder } -// Signal mocks base method +// Pid mocks base method. +func (m *MockProcess) Pid() int { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Pid") + ret0, _ := ret[0].(int) + return ret0 +} + +// Pid indicates an expected call of Pid. +func (mr *MockProcessMockRecorder) Pid() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Pid", reflect.TypeOf((*MockProcess)(nil).Pid)) +} + +// Signal mocks base method. func (m *MockProcess) Signal(arg0 os.Signal) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Signal", arg0) @@ -135,13 +150,13 @@ func (m *MockProcess) Signal(arg0 os.Signal) error { return ret0 } -// Signal indicates an expected call of Signal +// Signal indicates an expected call of Signal. func (mr *MockProcessMockRecorder) Signal(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Signal", reflect.TypeOf((*MockProcess)(nil).Signal), arg0) } -// Wait mocks base method +// Wait mocks base method. func (m *MockProcess) Wait() error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Wait") @@ -149,36 +164,36 @@ func (m *MockProcess) Wait() error { return ret0 } -// Wait indicates an expected call of Wait +// Wait indicates an expected call of Wait. func (mr *MockProcessMockRecorder) Wait() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Wait", reflect.TypeOf((*MockProcess)(nil).Wait)) } -// MockOSProcess is a mock of OSProcess interface +// MockOSProcess is a mock of OSProcess interface. type MockOSProcess struct { ctrl *gomock.Controller recorder *MockOSProcessMockRecorder } -// MockOSProcessMockRecorder is the mock recorder for MockOSProcess +// MockOSProcessMockRecorder is the mock recorder for MockOSProcess. type MockOSProcessMockRecorder struct { mock *MockOSProcess } -// NewMockOSProcess creates a new mock instance +// NewMockOSProcess creates a new mock instance. func NewMockOSProcess(ctrl *gomock.Controller) *MockOSProcess { mock := &MockOSProcess{ctrl: ctrl} mock.recorder = &MockOSProcessMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockOSProcess) EXPECT() *MockOSProcessMockRecorder { return m.recorder } -// Signal mocks base method +// Signal mocks base method. func (m *MockOSProcess) Signal(arg0 os.Signal) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Signal", arg0) @@ -186,13 +201,13 @@ func (m *MockOSProcess) Signal(arg0 os.Signal) error { return ret0 } -// Signal indicates an expected call of Signal +// Signal indicates an expected call of Signal. func (mr *MockOSProcessMockRecorder) Signal(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Signal", reflect.TypeOf((*MockOSProcess)(nil).Signal), arg0) } -// Wait mocks base method +// Wait mocks base method. func (m *MockOSProcess) Wait() (*os.ProcessState, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Wait") @@ -201,36 +216,36 @@ func (m *MockOSProcess) Wait() (*os.ProcessState, error) { return ret0, ret1 } -// Wait indicates an expected call of Wait +// Wait indicates an expected call of Wait. func (mr *MockOSProcessMockRecorder) Wait() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Wait", reflect.TypeOf((*MockOSProcess)(nil).Wait)) } -// MockExecCommandContext is a mock of ExecCommandContext interface +// MockExecCommandContext is a mock of ExecCommandContext interface. type MockExecCommandContext struct { ctrl *gomock.Controller recorder *MockExecCommandContextMockRecorder } -// MockExecCommandContextMockRecorder is the mock recorder for MockExecCommandContext +// MockExecCommandContextMockRecorder is the mock recorder for MockExecCommandContext. type MockExecCommandContextMockRecorder struct { mock *MockExecCommandContext } -// NewMockExecCommandContext creates a new mock instance +// NewMockExecCommandContext creates a new mock instance. func NewMockExecCommandContext(ctrl *gomock.Controller) *MockExecCommandContext { mock := &MockExecCommandContext{ctrl: ctrl} mock.recorder = &MockExecCommandContextMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockExecCommandContext) EXPECT() *MockExecCommandContextMockRecorder { return m.recorder } -// CommandContext mocks base method +// CommandContext mocks base method. func (m *MockExecCommandContext) CommandContext(arg0 context.Context, arg1 string, arg2 ...string) *exec.Cmd { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} @@ -242,37 +257,37 @@ func (m *MockExecCommandContext) CommandContext(arg0 context.Context, arg1 strin return ret0 } -// CommandContext indicates an expected call of CommandContext +// CommandContext indicates an expected call of CommandContext. func (mr *MockExecCommandContextMockRecorder) CommandContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{arg0, arg1}, arg2...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommandContext", reflect.TypeOf((*MockExecCommandContext)(nil).CommandContext), varargs...) } -// MockPacketListener is a mock of PacketListener interface +// MockPacketListener is a mock of PacketListener interface. type MockPacketListener struct { ctrl *gomock.Controller recorder *MockPacketListenerMockRecorder } -// MockPacketListenerMockRecorder is the mock recorder for MockPacketListener +// MockPacketListenerMockRecorder is the mock recorder for MockPacketListener. type MockPacketListenerMockRecorder struct { mock *MockPacketListener } -// NewMockPacketListener creates a new mock instance +// NewMockPacketListener creates a new mock instance. func NewMockPacketListener(ctrl *gomock.Controller) *MockPacketListener { mock := &MockPacketListener{ctrl: ctrl} mock.recorder = &MockPacketListenerMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockPacketListener) EXPECT() *MockPacketListenerMockRecorder { return m.recorder } -// ListenPacket mocks base method +// ListenPacket mocks base method. func (m *MockPacketListener) ListenPacket(arg0, arg1 string) (containerrun.PacketConnection, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ListenPacket", arg0, arg1) @@ -281,36 +296,36 @@ func (m *MockPacketListener) ListenPacket(arg0, arg1 string) (containerrun.Packe return ret0, ret1 } -// ListenPacket indicates an expected call of ListenPacket +// ListenPacket indicates an expected call of ListenPacket. func (mr *MockPacketListenerMockRecorder) ListenPacket(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListenPacket", reflect.TypeOf((*MockPacketListener)(nil).ListenPacket), arg0, arg1) } -// MockPacketConnection is a mock of PacketConnection interface +// MockPacketConnection is a mock of PacketConnection interface. type MockPacketConnection struct { ctrl *gomock.Controller recorder *MockPacketConnectionMockRecorder } -// MockPacketConnectionMockRecorder is the mock recorder for MockPacketConnection +// MockPacketConnectionMockRecorder is the mock recorder for MockPacketConnection. type MockPacketConnectionMockRecorder struct { mock *MockPacketConnection } -// NewMockPacketConnection creates a new mock instance +// NewMockPacketConnection creates a new mock instance. func NewMockPacketConnection(ctrl *gomock.Controller) *MockPacketConnection { mock := &MockPacketConnection{ctrl: ctrl} mock.recorder = &MockPacketConnectionMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockPacketConnection) EXPECT() *MockPacketConnectionMockRecorder { return m.recorder } -// Close mocks base method +// Close mocks base method. func (m *MockPacketConnection) Close() error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Close") @@ -318,13 +333,13 @@ func (m *MockPacketConnection) Close() error { return ret0 } -// Close indicates an expected call of Close +// Close indicates an expected call of Close. func (mr *MockPacketConnectionMockRecorder) Close() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockPacketConnection)(nil).Close)) } -// ReadFrom mocks base method +// ReadFrom mocks base method. func (m *MockPacketConnection) ReadFrom(arg0 []byte) (int, net.Addr, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ReadFrom", arg0) @@ -334,7 +349,7 @@ func (m *MockPacketConnection) ReadFrom(arg0 []byte) (int, net.Addr, error) { return ret0, ret1, ret2 } -// ReadFrom indicates an expected call of ReadFrom +// ReadFrom indicates an expected call of ReadFrom. func (mr *MockPacketConnectionMockRecorder) ReadFrom(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadFrom", reflect.TypeOf((*MockPacketConnection)(nil).ReadFrom), arg0) diff --git a/pkg/containerrun/mocks/mock_context.go b/pkg/containerrun/mocks/mock_context.go index cc0ec0c..0a1178b 100644 --- a/pkg/containerrun/mocks/mock_context.go +++ b/pkg/containerrun/mocks/mock_context.go @@ -5,35 +5,36 @@ package mocks import ( - gomock "github.com/golang/mock/gomock" reflect "reflect" time "time" + + gomock "github.com/golang/mock/gomock" ) -// MockContext is a mock of Context interface +// MockContext is a mock of Context interface. type MockContext struct { ctrl *gomock.Controller recorder *MockContextMockRecorder } -// MockContextMockRecorder is the mock recorder for MockContext +// MockContextMockRecorder is the mock recorder for MockContext. type MockContextMockRecorder struct { mock *MockContext } -// NewMockContext creates a new mock instance +// NewMockContext creates a new mock instance. func NewMockContext(ctrl *gomock.Controller) *MockContext { mock := &MockContext{ctrl: ctrl} mock.recorder = &MockContextMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockContext) EXPECT() *MockContextMockRecorder { return m.recorder } -// Deadline mocks base method +// Deadline mocks base method. func (m *MockContext) Deadline() (time.Time, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Deadline") @@ -42,13 +43,13 @@ func (m *MockContext) Deadline() (time.Time, bool) { return ret0, ret1 } -// Deadline indicates an expected call of Deadline +// Deadline indicates an expected call of Deadline. func (mr *MockContextMockRecorder) Deadline() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Deadline", reflect.TypeOf((*MockContext)(nil).Deadline)) } -// Done mocks base method +// Done mocks base method. func (m *MockContext) Done() <-chan struct{} { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Done") @@ -56,13 +57,13 @@ func (m *MockContext) Done() <-chan struct{} { return ret0 } -// Done indicates an expected call of Done +// Done indicates an expected call of Done. func (mr *MockContextMockRecorder) Done() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Done", reflect.TypeOf((*MockContext)(nil).Done)) } -// Err mocks base method +// Err mocks base method. func (m *MockContext) Err() error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Err") @@ -70,13 +71,13 @@ func (m *MockContext) Err() error { return ret0 } -// Err indicates an expected call of Err +// Err indicates an expected call of Err. func (mr *MockContextMockRecorder) Err() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Err", reflect.TypeOf((*MockContext)(nil).Err)) } -// Value mocks base method +// Value mocks base method. func (m *MockContext) Value(arg0 interface{}) interface{} { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Value", arg0) @@ -84,7 +85,7 @@ func (m *MockContext) Value(arg0 interface{}) interface{} { return ret0 } -// Value indicates an expected call of Value +// Value indicates an expected call of Value. func (mr *MockContextMockRecorder) Value(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Value", reflect.TypeOf((*MockContext)(nil).Value), arg0) From 77ebe22cc052ae7e86a5a4b585a8bd4f11c076a3 Mon Sep 17 00:00:00 2001 From: Jan Dubois Date: Tue, 18 May 2021 11:49:52 -0700 Subject: [PATCH 3/4] Update tests to pass in pid The pid is unused by the rest of the tests, so for now just set it to 0. Signed-off-by: Jan Dubois --- pkg/containerrun/containerrun_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/containerrun/containerrun_test.go b/pkg/containerrun/containerrun_test.go index 5330da0..8db9c89 100644 --- a/pkg/containerrun/containerrun_test.go +++ b/pkg/containerrun/containerrun_test.go @@ -990,7 +990,7 @@ var _ = Describe("ProcessRegistry", func() { var _ = Describe("ContainerProcess", func() { Context("NewContainerProcess", func() { It("constructs a new ContainerProcess", func() { - cp := NewContainerProcess(nil) + cp := NewContainerProcess(nil, 0) Expect(cp).ToNot(BeNil()) }) }) @@ -1008,7 +1008,7 @@ var _ = Describe("ContainerProcess", func() { It("is no-op if the process is not running", func() { p := NewMockOSProcess(ctrl) - cp := NewContainerProcess(p) + cp := NewContainerProcess(p, 0) p.EXPECT(). Signal(syscall.Signal(0)). @@ -1021,7 +1021,7 @@ var _ = Describe("ContainerProcess", func() { It("fails if signaling the unlerlying process fails", func() { p := NewMockOSProcess(ctrl) - cp := NewContainerProcess(p) + cp := NewContainerProcess(p, 0) sig := syscall.SIGTERM gomock.InOrder( @@ -1041,7 +1041,7 @@ var _ = Describe("ContainerProcess", func() { It("succeeds when signaling the underlying process succeeds", func() { p := NewMockOSProcess(ctrl) - cp := NewContainerProcess(p) + cp := NewContainerProcess(p, 0) sig := syscall.SIGTERM gomock.InOrder( @@ -1078,7 +1078,7 @@ var _ = Describe("ContainerProcess", func() { Return(nil, fmt.Errorf(`¯\_(ツ)_/¯`)). Times(1) - cp := NewContainerProcess(p) + cp := NewContainerProcess(p, 0) err := cp.Wait() Expect(err).To(Equal(fmt.Errorf(`failed to run process: ¯\_(ツ)_/¯`))) }) @@ -1091,7 +1091,7 @@ var _ = Describe("ContainerProcess", func() { Return(state, nil). Times(1) - cp := NewContainerProcess(p) + cp := NewContainerProcess(p, 0) err := cp.Wait() Expect(err).ToNot(HaveOccurred()) }) From 0048d5a1574d595aa70bf7f767d06e6c0f54a04b Mon Sep 17 00:00:00 2001 From: Andrew Edgar Date: Wed, 19 May 2021 09:52:59 -0600 Subject: [PATCH 4/4] New commit on top of Jan's for test fixes --- pkg/containerrun/containerrun.go | 20 ++++++-- pkg/containerrun/containerrun_test.go | 69 +++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/pkg/containerrun/containerrun.go b/pkg/containerrun/containerrun.go index 76afe27..9988351 100644 --- a/pkg/containerrun/containerrun.go +++ b/pkg/containerrun/containerrun.go @@ -53,6 +53,12 @@ type CmdRun func( postStartConditionCommandArgs []string, ) error +var basePath string = "/var/vcap" + +func SetBasePath(newPath string) { + basePath = newPath +} + func Run( runner Runner, conditionRunner Runner, @@ -233,7 +239,7 @@ func watchForCommands( errors chan error, commands chan processCommand, ) error { - sockAddr := fmt.Sprintf("/var/vcap/data/%s/%s_containerrun.sock", jobName, processName) + sockAddr := fmt.Sprintf("%s/data/%s/%s_containerrun.sock", basePath, jobName, processName) go func() { for { @@ -348,12 +354,16 @@ func startMainProcess( } processRegistry.Register(process) - sentinel := fmt.Sprintf("/var/vcap/data/%s/%s_containerrun.running", jobName, processName) + sentinel := fmt.Sprintf("%s/data/%s/%s_containerrun.running", basePath, jobName, processName) + err = os.MkdirAll(filepath.Dir(sentinel), 0755) + if err != nil { + return err + } err = ioutil.WriteFile(sentinel, nil, 0755) if err != nil { return err } - pidfile := fmt.Sprintf("/var/vcap/sys/run/bpm/%s/%s.pid", jobName, processName) + pidfile := fmt.Sprintf("%s/sys/run/bpm/%s/%s.pid", basePath, jobName, processName) err = os.MkdirAll(filepath.Dir(pidfile), 0755) if err != nil { return err @@ -550,14 +560,14 @@ type OSProcess interface { // ContainerProcess satisfies the Process interface. type ContainerProcess struct { process OSProcess - pid int + pid int } // NewContainerProcess constructs a new ContainerProcess. func NewContainerProcess(process OSProcess, pid int) *ContainerProcess { return &ContainerProcess{ process: process, - pid: pid, + pid: pid, } } diff --git a/pkg/containerrun/containerrun_test.go b/pkg/containerrun/containerrun_test.go index 8db9c89..1d8c2f8 100644 --- a/pkg/containerrun/containerrun_test.go +++ b/pkg/containerrun/containerrun_test.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "io/ioutil" + "log" "os" "os/exec" "sync" @@ -40,9 +41,16 @@ var _ = Describe("Run", func() { var ctrl *gomock.Controller var spinner *MockPacketListener + var tempDir string BeforeEach(func() { ctrl = gomock.NewController(GinkgoT()) + var err error + tempDir, err = ioutil.TempDir(os.TempDir(), "ginkgoTest") + if err != nil { + log.Fatal(err) + } + SetBasePath(tempDir) // Creating a listener spinning out an infinity of // empty packets when called upon. This keeps the @@ -81,6 +89,7 @@ var _ = Describe("Run", func() { AfterEach(func() { ctrl.Finish() + os.RemoveAll(tempDir) }) It("fails when args is empty", func() { @@ -106,6 +115,10 @@ var _ = Describe("Run", func() { Wait(). Return(fmt.Errorf(`¯\_(ツ)_/¯`)). Times(1) + process.EXPECT(). + Pid(). + Return(99). + Times(1) process.EXPECT(). Signal(gomock.Any()). Return(nil). @@ -126,6 +139,10 @@ var _ = Describe("Run", func() { Wait(). Return(nil). Times(1) + process.EXPECT(). + Pid(). + Return(99). + Times(1) process.EXPECT(). Signal(gomock.Any()). Return(nil). @@ -155,6 +172,10 @@ var _ = Describe("Run", func() { Wait(). Return(nil). Times(1) + process.EXPECT(). + Pid(). + Return(99). + Times(1) process.EXPECT(). Signal(gomock.Any()). Return(nil). @@ -192,6 +213,10 @@ var _ = Describe("Run", func() { Do(func() { time.Sleep(time.Second) }). Return(nil). AnyTimes() + process.EXPECT(). + Pid(). + Return(99). + Times(1) process.EXPECT(). Signal(gomock.Any()). Return(nil). @@ -227,6 +252,10 @@ var _ = Describe("Run", func() { Do(func() { time.Sleep(time.Second) }). Return(nil). AnyTimes() + process.EXPECT(). + Pid(). + Return(99). + Times(1) process.EXPECT(). Signal(gomock.Any()). Return(nil). @@ -271,6 +300,10 @@ var _ = Describe("Run", func() { Do(postStartWg.Wait). Return(nil). AnyTimes() + process.EXPECT(). + Pid(). + Return(99). + Times(1) process.EXPECT(). Signal(gomock.Any()). Return(nil). @@ -331,6 +364,10 @@ var _ = Describe("Run", func() { Do(func() { time.Sleep(time.Second) }). Return(nil). AnyTimes() + process.EXPECT(). + Pid(). + Return(99). + Times(1) process.EXPECT(). Signal(gomock.Any()). Return(nil). @@ -364,6 +401,10 @@ var _ = Describe("Run", func() { Do(postStartWg.Wait). Return(nil). AnyTimes() + process.EXPECT(). + Pid(). + Return(99). + Times(1) process.EXPECT(). Signal(gomock.Any()). Return(nil). @@ -431,6 +472,10 @@ var _ = Describe("Run", func() { Do(func() { time.Sleep(time.Second) }). Return(nil). Times(1) + process.EXPECT(). + Pid(). + Return(99). + Times(1) process.EXPECT(). Signal(os.Kill). Return(nil). @@ -498,6 +543,10 @@ var _ = Describe("Run", func() { Do(func() { trigger <- struct{}{}; time.Sleep(time.Second) }). Return(nil). Times(1) + process.EXPECT(). + Pid(). + Return(99). + Times(1) process.EXPECT(). Signal(os.Kill). Return(nil). @@ -563,6 +612,10 @@ var _ = Describe("Run", func() { Do(func() { trigger <- struct{}{}; time.Sleep(time.Second) }). Return(nil). Times(1) + process.EXPECT(). + Pid(). + Return(99). + Times(1) process.EXPECT(). Signal(os.Kill). Return(nil). @@ -630,6 +683,10 @@ var _ = Describe("Run", func() { gomock.InOrder( // Initial start, trigger `stop` // command, then wait for kill. + process.EXPECT(). + Pid(). + Return(99). + Times(1), process.EXPECT(). Wait(). Do(func() { trigger <- struct{}{}; <-killed }). @@ -637,6 +694,10 @@ var _ = Describe("Run", func() { Times(1), // Second start, via `start` command. // Be done. + process.EXPECT(). + Pid(). + Return(99). + Times(1), process.EXPECT(). Wait(). Return(nil). @@ -760,6 +821,10 @@ var _ = Describe("Run", func() { gomock.InOrder( // Initial start, trigger `stop` // command, then wait for kill. + process.EXPECT(). + Pid(). + Return(99). + Times(1), process.EXPECT(). Wait(). Do(func() { trigger <- struct{}{}; <-killed }). @@ -767,6 +832,10 @@ var _ = Describe("Run", func() { Times(1), // Second start, via `start` command. // Be done. + process.EXPECT(). + Pid(). + Return(99). + Times(1), process.EXPECT(). Wait(). Return(nil).