github.com/containerd/Containerd@v1.4.13/events.go (about)

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package containerd
    18  
    19  import (
    20  	"context"
    21  
    22  	eventsapi "github.com/containerd/containerd/api/services/events/v1"
    23  	"github.com/containerd/containerd/errdefs"
    24  	"github.com/containerd/containerd/events"
    25  	"github.com/containerd/typeurl"
    26  )
    27  
    28  // EventService handles the publish, forward and subscribe of events.
    29  type EventService interface {
    30  	events.Publisher
    31  	events.Forwarder
    32  	events.Subscriber
    33  }
    34  
    35  // NewEventServiceFromClient returns a new event service which communicates
    36  // over a GRPC connection.
    37  func NewEventServiceFromClient(client eventsapi.EventsClient) EventService {
    38  	return &eventRemote{
    39  		client: client,
    40  	}
    41  }
    42  
    43  type eventRemote struct {
    44  	client eventsapi.EventsClient
    45  }
    46  
    47  func (e *eventRemote) Publish(ctx context.Context, topic string, event events.Event) error {
    48  	any, err := typeurl.MarshalAny(event)
    49  	if err != nil {
    50  		return err
    51  	}
    52  	req := &eventsapi.PublishRequest{
    53  		Topic: topic,
    54  		Event: any,
    55  	}
    56  	if _, err := e.client.Publish(ctx, req); err != nil {
    57  		return errdefs.FromGRPC(err)
    58  	}
    59  	return nil
    60  }
    61  
    62  func (e *eventRemote) Forward(ctx context.Context, envelope *events.Envelope) error {
    63  	req := &eventsapi.ForwardRequest{
    64  		Envelope: &eventsapi.Envelope{
    65  			Timestamp: envelope.Timestamp,
    66  			Namespace: envelope.Namespace,
    67  			Topic:     envelope.Topic,
    68  			Event:     envelope.Event,
    69  		},
    70  	}
    71  	if _, err := e.client.Forward(ctx, req); err != nil {
    72  		return errdefs.FromGRPC(err)
    73  	}
    74  	return nil
    75  }
    76  
    77  func (e *eventRemote) Subscribe(ctx context.Context, filters ...string) (ch <-chan *events.Envelope, errs <-chan error) {
    78  	var (
    79  		evq  = make(chan *events.Envelope)
    80  		errq = make(chan error, 1)
    81  	)
    82  
    83  	errs = errq
    84  	ch = evq
    85  
    86  	session, err := e.client.Subscribe(ctx, &eventsapi.SubscribeRequest{
    87  		Filters: filters,
    88  	})
    89  	if err != nil {
    90  		errq <- err
    91  		close(errq)
    92  		return
    93  	}
    94  
    95  	go func() {
    96  		defer close(errq)
    97  
    98  		for {
    99  			ev, err := session.Recv()
   100  			if err != nil {
   101  				errq <- err
   102  				return
   103  			}
   104  
   105  			select {
   106  			case evq <- &events.Envelope{
   107  				Timestamp: ev.Timestamp,
   108  				Namespace: ev.Namespace,
   109  				Topic:     ev.Topic,
   110  				Event:     ev.Event,
   111  			}:
   112  			case <-ctx.Done():
   113  				if cerr := ctx.Err(); cerr != context.Canceled {
   114  					errq <- cerr
   115  				}
   116  				return
   117  			}
   118  		}
   119  	}()
   120  
   121  	return ch, errs
   122  }