Skip to content

Commit 37bb976

Browse files
committed
add event handling and graceful shutdown for artifacts
- Add `Artifact` event type in `config.go` and `events.go`. - Map `artStore.EventType` to standard libpod event statuses (Pull, Push, Remove, Create). - Spawn a `libartifactEvents` goroutine in `makeRuntime` to poll the event channel and write to the central eventer. - Implement graceful shutdown in `Runtime.Shutdown()` to process any pending artifact events safely before exiting. Signed-off-by: Byounguk Lee <nimdrak@gmail.com>
1 parent ef2117a commit 37bb976

3 files changed

Lines changed: 91 additions & 12 deletions

File tree

libpod/events/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ const (
122122
Container Type = "container"
123123
// Image - event is related to images
124124
Image Type = "image"
125+
// Artifact - event is related to artifacts
126+
Artifact Type = "artifact"
125127
// Network - event is related to networks
126128
Network Type = "network"
127129
// Pod - event is related to pods

libpod/events/events.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ func (s Status) String() string {
111111
// StringToType converts string to an EventType
112112
func StringToType(name string) (Type, error) {
113113
switch name {
114+
case Artifact.String():
115+
return Artifact, nil
114116
case Container.String():
115117
return Container, nil
116118
case Image.String():

libpod/runtime.go

Lines changed: 87 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -68,18 +68,19 @@ type Runtime struct {
6868
storageConfig storage.StoreOptions
6969
storageSet storageSet
7070

71-
state State
72-
store storage.Store
73-
storageService *storageService
74-
imageContext types.SystemContext
75-
defaultOCIRuntime OCIRuntime
76-
ociRuntimes map[string]OCIRuntime
77-
runtimeFlags []string
78-
network nettypes.ContainerNetwork
79-
conmonPath string
80-
libimageRuntime *libimage.Runtime
81-
libimageEventsShutdown chan bool
82-
lockManager lock.Manager
71+
state State
72+
store storage.Store
73+
storageService *storageService
74+
imageContext types.SystemContext
75+
defaultOCIRuntime OCIRuntime
76+
ociRuntimes map[string]OCIRuntime
77+
runtimeFlags []string
78+
network nettypes.ContainerNetwork
79+
conmonPath string
80+
libimageRuntime *libimage.Runtime
81+
libimageEventsShutdown chan bool
82+
libartifactEventsShutdown chan bool
83+
lockManager lock.Manager
8384

8485
// ArtifactStore returns the artifact store created from the runtime.
8586
ArtifactStore func() (*artStore.ArtifactStore, error)
@@ -503,6 +504,8 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) {
503504
runtime.ArtifactStore = sync.OnceValues(func() (*artStore.ArtifactStore, error) {
504505
return artStore.NewArtifactStore(filepath.Join(runtime.storageConfig.GraphRoot, "artifacts"), runtime.SystemContext())
505506
})
507+
// Run the libartifact events routine.
508+
runtime.libartifactEvents()
506509
}
507510

508511
// We now need to see if the system has restarted
@@ -722,6 +725,71 @@ func (r *Runtime) libimageEvents() {
722725
}()
723726
}
724727

728+
// libartifactEventsMap translates a libartifact event type to a libpod event status.
729+
var libartifactEventsMap = map[artStore.EventType]events.Status{
730+
artStore.EventTypeArtifactPull: events.Pull,
731+
artStore.EventTypeArtifactPush: events.Push,
732+
artStore.EventTypeArtifactRemove: events.Remove,
733+
artStore.EventTypeArtifactAdd: events.Create,
734+
}
735+
736+
// libartifactEvents spawns a goroutine which will listen for events on
737+
// the artStore.ArtifactStore. The goroutine will be cleaned up implicitly
738+
// when the main() exists.
739+
func (r *Runtime) libartifactEvents() {
740+
r.libartifactEventsShutdown = make(chan bool)
741+
742+
toLibpodEventStatus := func(e *artStore.Event) events.Status {
743+
status, found := libartifactEventsMap[e.Type]
744+
if !found {
745+
return "Unknown"
746+
}
747+
return status
748+
}
749+
750+
store, err := r.ArtifactStore()
751+
if err != nil {
752+
logrus.Errorf("Unable to initialize artifact store for events: %q", err)
753+
return
754+
}
755+
eventChannel := store.EventChannel()
756+
757+
go func() {
758+
sawShutdown := false
759+
for {
760+
// Make sure to read and write all events before
761+
// shutting down.
762+
for len(eventChannel) > 0 {
763+
libartifactEvent := <-eventChannel
764+
e := events.Event{
765+
ID: libartifactEvent.ID,
766+
Name: libartifactEvent.Name,
767+
Status: toLibpodEventStatus(libartifactEvent),
768+
Time: libartifactEvent.Time,
769+
Type: events.Artifact,
770+
}
771+
if libartifactEvent.Error != nil {
772+
e.Error = libartifactEvent.Error.Error()
773+
}
774+
if err := r.eventer.Write(e); err != nil {
775+
logrus.Errorf("Unable to write artifact event: %q", err)
776+
}
777+
}
778+
779+
if sawShutdown {
780+
close(r.libartifactEventsShutdown)
781+
return
782+
}
783+
784+
select {
785+
case <-r.libartifactEventsShutdown:
786+
sawShutdown = true
787+
case <-time.After(100 * time.Millisecond):
788+
}
789+
}
790+
}()
791+
}
792+
725793
// DeferredShutdown shuts down the runtime without exposing any
726794
// errors. This is only meant to be used when the runtime is being
727795
// shutdown within a defer statement; else use Shutdown
@@ -771,6 +839,13 @@ func (r *Runtime) Shutdown(force bool) error {
771839
<-r.libimageEventsShutdown
772840
}
773841

842+
if r.libartifactEventsShutdown != nil {
843+
// Tell loop to shutdown
844+
r.libartifactEventsShutdown <- true
845+
// Wait for close to signal shutdown
846+
<-r.libartifactEventsShutdown
847+
}
848+
774849
// Note that the libimage runtime shuts down the store.
775850
if err := r.libimageRuntime.Shutdown(force); err != nil {
776851
lastError = fmt.Errorf("shutting down container storage: %w", err)

0 commit comments

Comments
 (0)