Skip to content
This repository has been archived by the owner on Oct 22, 2021. It is now read-only.

Create pidfile and "bpm pid" command #11

Merged
merged 4 commits into from
May 20, 2021
Merged
Show file tree
Hide file tree
Changes from 3 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
2 changes: 2 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
log "github.com/sirupsen/logrus"
"os"

cmd "code.cloudfoundry.org/quarks-container-run/cmd/containerrun"
Expand All @@ -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)
}
}
41 changes: 25 additions & 16 deletions pkg/containerrun/bpm.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ 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
}

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
Expand All @@ -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
Expand All @@ -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) {
Expand Down
34 changes: 28 additions & 6 deletions pkg/containerrun/containerrun.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"os"
"os/exec"
"os/signal"
"path/filepath"
"strconv"
"strings"
"sync"
"syscall"
Expand Down Expand Up @@ -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)
jandubois marked this conversation as resolved.
Show resolved Hide resolved
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{}{}
}()

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand All @@ -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,
}
}

Expand Down Expand Up @@ -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
Expand Down
12 changes: 6 additions & 6 deletions pkg/containerrun/containerrun_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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())
})
})
Expand All @@ -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)).
Expand All @@ -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(
Expand All @@ -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(
Expand Down Expand Up @@ -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: ¯\_(ツ)_/¯`)))
})
Expand All @@ -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())
})
Expand Down
Loading