Skip to content

Commit 44a5293

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 - Spawn a `libartifactEvents` goroutine in `makeRuntime` to poll the event channel and write to the eventer. - Implement graceful shutdown in `Runtime.Shutdown()` Signed-off-by: Byounguk Lee <nimdrak@gmail.com>
1 parent ef2117a commit 44a5293

3 files changed

Lines changed: 90 additions & 13 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: 86 additions & 13 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)
@@ -501,7 +502,12 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) {
501502

502503
// Using sync once value to only init the store exactly once and only when it will be actually be used.
503504
runtime.ArtifactStore = sync.OnceValues(func() (*artStore.ArtifactStore, error) {
504-
return artStore.NewArtifactStore(filepath.Join(runtime.storageConfig.GraphRoot, "artifacts"), runtime.SystemContext())
505+
artifactStore, err := artStore.NewArtifactStore(filepath.Join(runtime.storageConfig.GraphRoot, "artifacts"), runtime.SystemContext())
506+
if err != nil {
507+
return nil, err
508+
}
509+
runtime.libartifactEvents(artifactStore)
510+
return artifactStore, nil
505511
})
506512
}
507513

@@ -722,6 +728,66 @@ func (r *Runtime) libimageEvents() {
722728
}()
723729
}
724730

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

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

0 commit comments

Comments
 (0)