diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go index dfb436c..c5b3b80 100644 --- a/internal/pkg/config/config.go +++ b/internal/pkg/config/config.go @@ -118,8 +118,8 @@ func Init(conn context.Context) error { return err } Containers, Networks = p.Containers, p.Networks - for i := range p.Containers { - p.Containers[i].Init(conn, Networks) + for i := range Containers { + Containers[i].Init(conn, Networks) } slices.SortFunc(Containers, func(a, b container.Container) bool { return a.Name < b.Name diff --git a/internal/pkg/container/container.go b/internal/pkg/container/container.go index dc658c7..0cc13a9 100644 --- a/internal/pkg/container/container.go +++ b/internal/pkg/container/container.go @@ -27,6 +27,7 @@ import ( "fmt" "net" "os/exec" + "sync" cmd "gitea.elkins.co/Networking/ccl/internal/pkg/command" "gitea.elkins.co/Networking/ccl/internal/pkg/network" @@ -61,6 +62,7 @@ type Container struct { conn context.Context cdata *define.InspectContainerData + cdataLock sync.Mutex wasRunning bool } @@ -105,19 +107,23 @@ func (c *Container) Init(conn context.Context, nets []network.Network) error { return fmt.Errorf("conn is nil: %s", c.Name) } c.conn = conn + + c.cdataLock.Lock() + defer c.cdataLock.Unlock() err := c.populateCData() - c.wasRunning = err != nil && c.IsRunning() + c.wasRunning = c.IsRunning() return err } func (c *Container) LogEntry() *log.Entry { f := log.Fields{ "container": c.Name, + "wasRunning": c.wasRunning, } if c.cdata != nil && c.cdata.ID != "" { f["id"] = c.cdata.ID[:12] + "…" } - if c.cdata.State != nil { + if c.cdata != nil && c.cdata.State != nil { f["state"] = c.cdata.State.Status } return log.WithFields(f) @@ -239,6 +245,8 @@ func (c *Container) CreateCommands() cmd.CommandSet { }), cmd.NewFunc("validate_spec", spec.Validate), cmd.NewFunc("do_create", func() error { + c.cdataLock.Lock() + defer c.cdataLock.Unlock() _, err := containers.CreateWithSpec(c.conn, &spec, nil) if err != nil { return err @@ -259,11 +267,15 @@ func (c *Container) RecreateCommands() cmd.CommandSet { func (c *Container) RemoveCommands() cmd.CommandSet { return c.newCommandSet("remove", cmd.Commands{ cmd.NewFunc("remove_if_exists", func() error { + c.cdataLock.Lock() + defer c.cdataLock.Unlock() + c.populateCData() if c.cdata.ID == "" { return nil } yes := true _, err := containers.Remove(c.conn, c.cdata.ID, &containers.RemoveOptions{Force: &yes}) + c.cdata = nil return err }), }) @@ -272,6 +284,9 @@ func (c *Container) RemoveCommands() cmd.CommandSet { func (c *Container) StartCommands() cmd.CommandSet { return c.newCommandSet("START", cmd.Commands{ cmd.NewFunc("start_container", func() error { + c.cdataLock.Lock() + defer c.cdataLock.Unlock() + c.populateCData() if c.IsRunning() { c.LogEntry().Debugln("Container start was commanded but it is already running. Not a problem.") return nil @@ -327,18 +342,19 @@ func (c *Container) UpdateCommands() cmd.CommandSet { } func (c *Container) ConditionalStartCommands() cmd.CommandSet { - return c.newCommandSet("CONDSTART", cmd.Commands{ - cmd.NewConditional("restart_if_was_running", - func() bool { return c.wasRunning }, - cmd.NewSet(c.StartCommands()), - cmd.NewNop(), - ), + if c.wasRunning { + return c.StartCommands() + } + return c.newCommandSet("NOP", cmd.Commands{ + cmd.NewNop(), }) } func (c *Container) StopCommands() cmd.CommandSet { return c.newCommandSet("STOP", cmd.Commands{ cmd.NewFunc("stop_if_running", func() error { + c.cdataLock.Lock() + defer c.cdataLock.Unlock() if !c.IsRunning() { c.LogEntry().Debugln("Container stop was commanded but it wasn't running. Not a problem.") return nil @@ -362,14 +378,11 @@ func (c *Container) StopCommands() cmd.CommandSet { } func (c *Container) populateCData() error { - // TODO: locking? + c.cdata = nil var err error no := false c.cdata, err = containers.Inspect(c.conn, c.Name, &containers.InspectOptions{Size: &no}) - if err != nil { - return err - } - return nil + return err } func (c *Container) Pid() int {