Skip to content

Commit 3a30429

Browse files
goonzoidChristopher Brown
authored andcommitted
runc/lifecycle: use error to express missing processes
We modelled the renamed StatProcess function on the os.Stat function from the standard library. This means that we can safely say that if the error is nil then there will always be a process returned. The IsNotExist function was added to check for the missing process error case. This check was then added to the shell command so that the user does not see an internal error message with internal container names. * Re-ordered and re-grouped some imports so that bpm imports are at the bottom. * Renamed job to process where necessary. * Use the state of a process instead of its PID to see if it has failed. * Do not try to start a job if there is an error trying to fetch existing process state. [finishes #156173439] Signed-off-by: Christopher Brown <cbrown@pivotal.io>
1 parent 0ea421a commit 3a30429

File tree

11 files changed

+98
-77
lines changed

11 files changed

+98
-77
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# v0.6.0
22

33
* change ownership of `/etc/profile.d/bpm.sh` to `vcap` group
4+
* improved consistency of error messages
45

56
# v0.5.0
67

src/bpm/commands/pid.go

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ import (
2020
"fmt"
2121

2222
"github.com/spf13/cobra"
23+
24+
"bpm/models"
25+
"bpm/runc/lifecycle"
2326
)
2427

2528
func init() {
@@ -43,20 +46,14 @@ func pidForJob(cmd *cobra.Command, _ []string) error {
4346
cmd.SilenceUsage = true
4447

4548
runcLifecycle := newRuncLifecycle()
46-
job, err := runcLifecycle.GetProcess(bpmCfg)
47-
if err != nil {
48-
return fmt.Errorf("failed to get job: %s", err.Error())
49-
}
50-
51-
if job == nil {
52-
return errors.New("job is not running")
53-
}
54-
55-
if job.Pid <= 0 {
56-
return errors.New("no pid for job")
49+
process, err := runcLifecycle.StatProcess(bpmCfg)
50+
if lifecycle.IsNotExist(err) || process.Status == models.ProcessStateFailed {
51+
return errors.New("process is not running or could not be found")
52+
} else if err != nil {
53+
return fmt.Errorf("failed to get job: %s", err)
5754
}
5855

59-
fmt.Fprintf(cmd.OutOrStdout(), "%d\n", job.Pid)
56+
fmt.Fprintf(cmd.OutOrStdout(), "%d\n", process.Pid)
6057

6158
return nil
6259
}

src/bpm/commands/shell.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,14 @@
1616
package commands
1717

1818
import (
19+
"errors"
20+
"fmt"
1921
"os"
2022

2123
"github.com/spf13/cobra"
24+
25+
"bpm/models"
26+
"bpm/runc/lifecycle"
2227
)
2328

2429
func init() {
@@ -42,5 +47,13 @@ func shell(cmd *cobra.Command, _ []string) error {
4247
cmd.SilenceUsage = true
4348

4449
runcLifecycle := newRuncLifecycle()
50+
51+
process, err := runcLifecycle.StatProcess(bpmCfg)
52+
if lifecycle.IsNotExist(err) || process.Status == models.ProcessStateFailed {
53+
return errors.New("process is not running or could not be found")
54+
} else if err != nil {
55+
return fmt.Errorf("failed to get process: %s", err)
56+
}
57+
4558
return runcLifecycle.OpenShell(bpmCfg, os.Stdin, cmd.OutOrStdout(), cmd.OutOrStderr())
4659
}

src/bpm/commands/start.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package commands
1818
import (
1919
"bpm/config"
2020
"bpm/models"
21+
"bpm/runc/lifecycle"
2122
"fmt"
2223

2324
"github.com/spf13/cobra"
@@ -72,14 +73,15 @@ func start(cmd *cobra.Command, _ []string) error {
7273
}
7374

7475
runcLifecycle := newRuncLifecycle()
75-
job, err := runcLifecycle.GetProcess(bpmCfg)
76-
if err != nil {
76+
process, err := runcLifecycle.StatProcess(bpmCfg)
77+
if err != nil && !lifecycle.IsNotExist(err) {
7778
logger.Error("failed-getting-job", err)
79+
return err
7880
}
7981

8082
var state string
81-
if job != nil {
82-
state = job.Status
83+
if process != nil {
84+
state = process.Status
8385
}
8486

8587
switch state {

src/bpm/commands/stop.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import (
2020
"time"
2121

2222
"github.com/spf13/cobra"
23+
24+
"bpm/runc/lifecycle"
2325
)
2426

2527
const DefaultStopTimeout = 20 * time.Second
@@ -61,19 +63,16 @@ func stop(cmd *cobra.Command, _ []string) error {
6163
defer logger.Info("complete")
6264

6365
runcLifecycle := newRuncLifecycle()
64-
job, err := runcLifecycle.GetProcess(bpmCfg)
65-
if err != nil {
66-
logger.Error("failed-to-get-job", err)
67-
return fmt.Errorf("failed to get job-process status: %s", err)
68-
}
6966

70-
if job == nil {
67+
if _, err := runcLifecycle.StatProcess(bpmCfg); lifecycle.IsNotExist(err) {
7168
logger.Info("job-already-stopped")
7269
return nil
70+
} else if err != nil {
71+
logger.Error("failed-to-get-job", err)
72+
return fmt.Errorf("failed to get job-process status: %s", err)
7373
}
7474

75-
err = runcLifecycle.StopProcess(logger, bpmCfg, DefaultStopTimeout)
76-
if err != nil {
75+
if err := runcLifecycle.StopProcess(logger, bpmCfg, DefaultStopTimeout); err != nil {
7776
logger.Error("failed-to-stop", err)
7877
}
7978

src/bpm/commands/trace.go

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ import (
2323
"os/signal"
2424

2525
"github.com/spf13/cobra"
26+
27+
"bpm/models"
28+
"bpm/runc/lifecycle"
2629
)
2730

2831
var longText = `
@@ -57,20 +60,15 @@ func trace(cmd *cobra.Command, _ []string) error {
5760
cmd.SilenceUsage = true
5861

5962
runcLifecycle := newRuncLifecycle()
60-
job, err := runcLifecycle.GetProcess(bpmCfg)
61-
if err != nil {
62-
return fmt.Errorf("failed to get job: %s", err.Error())
63-
}
64-
65-
if job == nil {
66-
return errors.New("job is not running")
67-
}
6863

69-
if job.Pid <= 0 {
70-
return errors.New("no pid for job")
64+
process, err := runcLifecycle.StatProcess(bpmCfg)
65+
if lifecycle.IsNotExist(err) || process.Status == models.ProcessStateFailed {
66+
return errors.New("process is not running or could not be found")
67+
} else if err != nil {
68+
return fmt.Errorf("failed to get process: %s", err)
7169
}
7270

73-
straceCmd := exec.Command("strace", "-s", "100", "-f", "-y", "-yy", "-p", fmt.Sprintf("%d", job.Pid))
71+
straceCmd := exec.Command("strace", "-s", "100", "-f", "-y", "-yy", "-p", fmt.Sprintf("%d", process.Pid))
7472
straceCmd.Stdin = os.Stdin
7573
straceCmd.Stdout = cmd.OutOrStdout()
7674
straceCmd.Stderr = cmd.OutOrStderr()

src/bpm/integration/pid_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ var _ = Describe("pid", func() {
9494
Expect(err).ShouldNot(HaveOccurred())
9595

9696
Eventually(session).Should(gexec.Exit(1))
97-
Expect(session.Err).Should(gbytes.Say("Error: no pid for job"))
97+
Expect(session.Err).Should(gbytes.Say("Error: process is not running or could not be found"))
9898
})
9999
})
100100

@@ -104,7 +104,7 @@ var _ = Describe("pid", func() {
104104
Expect(err).ShouldNot(HaveOccurred())
105105

106106
Eventually(session).Should(gexec.Exit(1))
107-
Expect(session.Err).Should(gbytes.Say("Error: job is not running"))
107+
Expect(session.Err).Should(gbytes.Say("Error: process is not running or could not be found"))
108108
})
109109
})
110110

src/bpm/integration/shell_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ var _ = Describe("start", func() {
125125
session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
126126
Expect(err).ShouldNot(HaveOccurred())
127127
Eventually(session).Should(gexec.Exit(1))
128-
Expect(session.Err).Should(gbytes.Say("does not exist"))
128+
Expect(session.Err).Should(gbytes.Say("process is not running or could not be found"))
129129
})
130130
})
131131

src/bpm/integration/trace_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ var _ = Describe("trace", func() {
9494
session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
9595
Expect(err).ShouldNot(HaveOccurred())
9696
Eventually(session).Should(gexec.Exit(1))
97-
Expect(session.Err).Should(gbytes.Say("Error: no pid for job"))
97+
Expect(session.Err).Should(gbytes.Say("Error: process is not running or could not be found"))
9898
})
9999
})
100100

@@ -103,7 +103,7 @@ var _ = Describe("trace", func() {
103103
session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
104104
Expect(err).ShouldNot(HaveOccurred())
105105
Eventually(session).Should(gexec.Exit(1))
106-
Expect(session.Err).Should(gbytes.Say("Error: job is not running"))
106+
Expect(session.Err).Should(gbytes.Say("Error: process is not running or could not be found"))
107107
})
108108
})
109109

src/bpm/runc/lifecycle/lifecycle.go

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,32 +16,41 @@
1616
package lifecycle
1717

1818
import (
19-
"bpm/config"
20-
"bpm/models"
21-
"bpm/runc/client"
22-
"bpm/usertools"
2319
"errors"
2420
"fmt"
2521
"io"
2622
"os"
2723
"os/exec"
2824
"time"
2925

30-
"github.com/opencontainers/runtime-spec/specs-go"
26+
specs "github.com/opencontainers/runtime-spec/specs-go"
3127

3228
"code.cloudfoundry.org/clock"
3329
"code.cloudfoundry.org/lager"
30+
31+
"bpm/config"
32+
"bpm/models"
33+
"bpm/runc/client"
34+
"bpm/usertools"
3435
)
3536

3637
const (
3738
ContainerSigQuitGracePeriod = 5 * time.Second
3839
ContainerStatePollInterval = 1 * time.Second
39-
ContainerStateRunning = "running"
40-
ContainerStatePaused = "paused"
41-
ContainerStateStopped = "stopped"
40+
41+
ContainerStateRunning = "running"
42+
ContainerStatePaused = "paused"
43+
ContainerStateStopped = "stopped"
4244
)
4345

44-
var TimeoutError = errors.New("failed to stop job within timeout")
46+
var (
47+
timeoutError = errors.New("failed to stop job within timeout")
48+
isNotExistError = errors.New("process is not running or could not be found")
49+
)
50+
51+
func IsNotExist(err error) bool {
52+
return err == isNotExistError
53+
}
4554

4655
//go:generate counterfeiter . UserFinder
4756

@@ -151,18 +160,14 @@ func (j *RuncLifecycle) StartProcess(logger lager.Logger, bpmCfg *config.BPMConf
151160
)
152161
}
153162

154-
// GetProcess returns the following:
155-
// - process, nil if the process is running (and no errors were encountered)
156-
// - nil,nil if the process is not running and there is no other error
157-
// - nil,error if there is any other error getting the process beyond it not running
158-
func (j *RuncLifecycle) GetProcess(cfg *config.BPMConfig) (*models.Process, error) {
163+
func (j *RuncLifecycle) StatProcess(cfg *config.BPMConfig) (*models.Process, error) {
159164
container, err := j.runcClient.ContainerState(cfg.ContainerID())
160165
if err != nil {
161166
return nil, err
162167
}
163168

164169
if container == nil {
165-
return nil, nil
170+
return nil, isNotExistError
166171
}
167172

168173
return newProcessFromContainerState(
@@ -231,7 +236,7 @@ func (j *RuncLifecycle) StopProcess(logger lager.Logger, cfg *config.BPMConfig,
231236
}
232237

233238
j.clock.Sleep(ContainerSigQuitGracePeriod)
234-
return TimeoutError
239+
return timeoutError
235240
}
236241
}
237242
}

0 commit comments

Comments
 (0)