refactor: container status constants

This commit is contained in:
Rob Watson 2025-03-05 04:51:06 +01:00
parent f5bfa62330
commit e3ca34e8e0
8 changed files with 45 additions and 33 deletions

2
.gitignore vendored
View File

@ -1,2 +1,2 @@
/octoplex.log
*.log
/mediamtx.yml

View File

@ -185,7 +185,7 @@ func (a *Client) RunContainer(ctx context.Context, params RunContainerParams) (<
sendError(fmt.Errorf("container create: %w", err))
return
}
containerStateC <- domain.Container{ID: createResp.ID, State: "created"}
containerStateC <- domain.Container{ID: createResp.ID, Status: domain.ContainerStatusCreated}
if err = a.apiClient.NetworkConnect(ctx, a.networkID, createResp.ID, nil); err != nil {
sendError(fmt.Errorf("network connect: %w", err))
@ -198,7 +198,7 @@ func (a *Client) RunContainer(ctx context.Context, params RunContainerParams) (<
}
a.logger.Info("Started container", "id", shortID(createResp.ID), "duration", time.Since(now))
containerStateC <- domain.Container{ID: createResp.ID, State: "running"}
containerStateC <- domain.Container{ID: createResp.ID, Status: domain.ContainerStatusRunning}
a.runContainerLoop(ctx, createResp.ID, params.NetworkCountConfig, containerStateC, errC)
}()
@ -216,7 +216,7 @@ func (a *Client) pullImageIfNeeded(ctx context.Context, imageName string, contai
return nil
}
containerStateC <- domain.Container{State: "pulling"}
containerStateC <- domain.Container{Status: domain.ContainerStatusPulling}
pullReader, err := a.apiClient.ImagePull(ctx, imageName, image.PullOptions{})
if err != nil {
@ -292,7 +292,7 @@ func (a *Client) runContainerLoop(
}
}()
state := &domain.Container{ID: containerID, State: "running"}
state := &domain.Container{ID: containerID, Status: domain.ContainerStatusRunning}
sendState := func() { stateC <- *state }
sendState()
@ -308,7 +308,7 @@ func (a *Client) runContainerLoop(
containerState = "exited"
}
state.State = containerState
state.Status = containerState
state.CPUPercent = 0
state.MemoryUsageBytes = 0
state.HealthState = "unhealthy"
@ -338,7 +338,7 @@ func (a *Client) runContainerLoop(
}
if evt.Action == "start" {
state.State = "running"
state.Status = domain.ContainerStatusRunning
sendState()
continue
}

View File

@ -89,10 +89,10 @@ func TestClientRunContainer(t *testing.T) {
require.NoError(t, <-errC)
}()
assert.Equal(t, "pulling", (<-containerStateC).State)
assert.Equal(t, "created", (<-containerStateC).State)
assert.Equal(t, "running", (<-containerStateC).State)
assert.Equal(t, "running", (<-containerStateC).State)
assert.Equal(t, "pulling", (<-containerStateC).Status)
assert.Equal(t, "created", (<-containerStateC).Status)
assert.Equal(t, "running", (<-containerStateC).Status)
assert.Equal(t, "running", (<-containerStateC).Status)
// Enough time for events channel to receive a message:
time.Sleep(100 * time.Millisecond)
@ -100,7 +100,7 @@ func TestClientRunContainer(t *testing.T) {
containerWaitC <- dockercontainer.WaitResponse{StatusCode: 1}
state := <-containerStateC
assert.Equal(t, "exited", state.State)
assert.Equal(t, "exited", state.Status)
assert.Equal(t, "unhealthy", state.HealthState)
require.NotNil(t, state.ExitCode)
assert.Equal(t, 1, *state.ExitCode)
@ -146,8 +146,8 @@ func TestClientRunContainerErrorStartingContainer(t *testing.T) {
HostConfig: &dockercontainer.HostConfig{},
})
assert.Equal(t, "pulling", (<-containerStateC).State)
assert.Equal(t, "created", (<-containerStateC).State)
assert.Equal(t, "pulling", (<-containerStateC).Status)
assert.Equal(t, "created", (<-containerStateC).Status)
err = <-errC
require.EqualError(t, err, "container start: error starting container")

View File

@ -9,6 +9,7 @@ import (
"time"
"git.netflux.io/rob/octoplex/container"
"git.netflux.io/rob/octoplex/domain"
"git.netflux.io/rob/octoplex/shortid"
"git.netflux.io/rob/octoplex/testhelpers"
typescontainer "github.com/docker/docker/api/types/container"
@ -196,11 +197,11 @@ func TestContainerRestart(t *testing.T) {
testhelpers.ChanRequireNoError(t, errC)
containerState := <-containerStateC
assert.Equal(t, "pulling", containerState.State)
assert.Equal(t, "pulling", containerState.Status)
containerState = <-containerStateC
assert.Equal(t, "created", containerState.State)
assert.Equal(t, "created", containerState.Status)
containerState = <-containerStateC
assert.Equal(t, "running", containerState.State)
assert.Equal(t, "running", containerState.Status)
err = nil // reset error
done := make(chan struct{})
@ -210,9 +211,9 @@ func TestContainerRestart(t *testing.T) {
var count int
for {
containerState = <-containerStateC
if containerState.State == "restarting" {
if containerState.Status == domain.ContainerStatusRestarting {
break
} else if containerState.State == "exited" {
} else if containerState.Status == domain.ContainerStatusExited {
err = errors.New("container exited unexpectedly")
} else if count >= 5 {
err = errors.New("container did not enter restarting state")

View File

@ -55,13 +55,24 @@ type Destination struct {
URL string
}
// Container represents the current state of an individual container.
// Container status strings.
//
// The source of truth is always the Docker daemon, this struct is used only
// for passing asynchronous state.
// TODO: refactor to strictly reflect Docker status strings.
const (
ContainerStatusPulling = "pulling" // Does not correspond to a Docker status.
ContainerStatusCreated = "created"
ContainerStatusRunning = "running"
ContainerStatusPaused = "paused"
ContainerStatusRestarting = "restarting"
ContainerStatusRemoving = "removing"
ContainerStatusExited = "exited"
ContainerStatusDead = "dead"
)
// Container represents the current state of an individual container.
type Container struct {
ID string
State string
Status string
HealthState string
CPUPercent float64
MemoryUsageBytes uint64

View File

@ -172,7 +172,7 @@ func (s *Actor) actorLoop(containerStateC <-chan domain.Container, errC <-chan e
case containerState := <-containerStateC:
s.state.Container = containerState
if s.state.Container.State == "exited" {
if s.state.Container.Status == domain.ContainerStatusExited {
fetchStateT.Stop()
s.handleContainerExit(nil)
}

View File

@ -146,7 +146,7 @@ func (a *Actor) destLoop(url string, containerStateC <-chan domain.Container, er
case containerState := <-containerStateC:
state.Container = containerState
if containerState.State == "running" {
if containerState.Status == "running" {
if hasElapsedSince(5*time.Second, containerState.RxSince) {
state.Status = domain.DestinationStatusLive
} else {

View File

@ -326,7 +326,7 @@ func (ui *UI) redrawFromState(state domain.AppState) {
}
ui.sourceViews.status.SetText("[black:green]receiving" + durStr)
} else if state.Source.Container.State == "running" && state.Source.Container.HealthState == "healthy" {
} else if state.Source.Container.Status == domain.ContainerStatusRunning && state.Source.Container.HealthState == "healthy" {
ui.sourceViews.status.SetText("[black:yellow]ready")
} else {
ui.sourceViews.status.SetText("[white:red]not ready")
@ -335,19 +335,19 @@ func (ui *UI) redrawFromState(state domain.AppState) {
ui.sourceViews.health.SetText("[white]" + cmp.Or(rightPad(state.Source.Container.HealthState, 9), dash))
cpuPercent := dash
if state.Source.Container.State == "running" {
if state.Source.Container.Status == domain.ContainerStatusRunning {
cpuPercent = fmt.Sprintf("%.1f", state.Source.Container.CPUPercent)
}
ui.sourceViews.cpu.SetText("[white]" + cpuPercent)
memUsage := dash
if state.Source.Container.State == "running" {
if state.Source.Container.Status == domain.ContainerStatusRunning {
memUsage = fmt.Sprintf("%.1f", float64(state.Source.Container.MemoryUsageBytes)/1024/1024)
}
ui.sourceViews.mem.SetText("[white]" + memUsage)
rxRate := dash
if state.Source.Container.State == "running" {
if state.Source.Container.Status == domain.ContainerStatusRunning {
rxRate = fmt.Sprintf("%d", state.Source.Container.RxRate)
}
ui.sourceViews.rx.SetText("[white]" + rxRate)
@ -385,7 +385,7 @@ func (ui *UI) redrawFromState(state domain.AppState) {
ui.destView.SetCell(i+1, 2, tview.NewTableCell("[white]"+rightPad("off-air", statusLen)))
}
ui.destView.SetCell(i+1, 3, tview.NewTableCell("[white]"+rightPad(cmp.Or(dest.Container.State, dash), 10)))
ui.destView.SetCell(i+1, 3, tview.NewTableCell("[white]"+rightPad(cmp.Or(dest.Container.Status, dash), 10)))
healthState := dash
if dest.Status == domain.DestinationStatusLive {
@ -394,19 +394,19 @@ func (ui *UI) redrawFromState(state domain.AppState) {
ui.destView.SetCell(i+1, 4, tview.NewTableCell("[white]"+rightPad(healthState, 7)))
cpuPercent := dash
if dest.Container.State == "running" {
if dest.Container.Status == domain.ContainerStatusRunning {
cpuPercent = fmt.Sprintf("%.1f", dest.Container.CPUPercent)
}
ui.destView.SetCell(i+1, 5, tview.NewTableCell("[white]"+rightPad(cpuPercent, 4)))
memoryUsage := dash
if dest.Container.State == "running" {
if dest.Container.Status == domain.ContainerStatusRunning {
memoryUsage = fmt.Sprintf("%.1f", float64(dest.Container.MemoryUsageBytes)/1000/1000)
}
ui.destView.SetCell(i+1, 6, tview.NewTableCell("[white]"+rightPad(memoryUsage, 4)))
txRate := dash
if dest.Container.State == "running" {
if dest.Container.Status == domain.ContainerStatusRunning {
txRate = "[white]" + rightPad(strconv.Itoa(dest.Container.TxRate), 4)
}
ui.destView.SetCell(i+1, 7, tview.NewTableCell(txRate))