github.com/lalkh/containerd@v1.4.3/cmd/containerd/command/publish.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 command 18 19 import ( 20 gocontext "context" 21 "io" 22 "io/ioutil" 23 "net" 24 "os" 25 "time" 26 27 eventsapi "github.com/containerd/containerd/api/services/events/v1" 28 "github.com/containerd/containerd/errdefs" 29 "github.com/containerd/containerd/namespaces" 30 "github.com/containerd/containerd/pkg/dialer" 31 "github.com/gogo/protobuf/types" 32 "github.com/pkg/errors" 33 "github.com/urfave/cli" 34 "google.golang.org/grpc" 35 "google.golang.org/grpc/backoff" 36 ) 37 38 var publishCommand = cli.Command{ 39 Name: "publish", 40 Usage: "binary to publish events to containerd", 41 Flags: []cli.Flag{ 42 cli.StringFlag{ 43 Name: "namespace", 44 Usage: "namespace to publish to", 45 }, 46 cli.StringFlag{ 47 Name: "topic", 48 Usage: "topic of the event", 49 }, 50 }, 51 Action: func(context *cli.Context) error { 52 ctx := namespaces.WithNamespace(gocontext.Background(), context.String("namespace")) 53 topic := context.String("topic") 54 if topic == "" { 55 return errors.Wrap(errdefs.ErrInvalidArgument, "topic required to publish event") 56 } 57 payload, err := getEventPayload(os.Stdin) 58 if err != nil { 59 return err 60 } 61 client, err := connectEvents(context.GlobalString("address")) 62 if err != nil { 63 return err 64 } 65 if _, err := client.Publish(ctx, &eventsapi.PublishRequest{ 66 Topic: topic, 67 Event: payload, 68 }); err != nil { 69 return errdefs.FromGRPC(err) 70 } 71 return nil 72 }, 73 } 74 75 func getEventPayload(r io.Reader) (*types.Any, error) { 76 data, err := ioutil.ReadAll(r) 77 if err != nil { 78 return nil, err 79 } 80 var any types.Any 81 if err := any.Unmarshal(data); err != nil { 82 return nil, err 83 } 84 return &any, nil 85 } 86 87 func connectEvents(address string) (eventsapi.EventsClient, error) { 88 conn, err := connect(address, dialer.ContextDialer) 89 if err != nil { 90 return nil, errors.Wrapf(err, "failed to dial %q", address) 91 } 92 return eventsapi.NewEventsClient(conn), nil 93 } 94 95 func connect(address string, d func(gocontext.Context, string) (net.Conn, error)) (*grpc.ClientConn, error) { 96 backoffConfig := backoff.DefaultConfig 97 backoffConfig.MaxDelay = 3 * time.Second 98 connParams := grpc.ConnectParams{ 99 Backoff: backoffConfig, 100 } 101 gopts := []grpc.DialOption{ 102 grpc.WithBlock(), 103 grpc.WithInsecure(), 104 grpc.WithContextDialer(d), 105 grpc.FailOnNonTempDialError(true), 106 grpc.WithConnectParams(connParams), 107 } 108 ctx, cancel := gocontext.WithTimeout(gocontext.Background(), 2*time.Second) 109 defer cancel() 110 conn, err := grpc.DialContext(ctx, dialer.DialAddress(address), gopts...) 111 if err != nil { 112 return nil, errors.Wrapf(err, "failed to dial %q", address) 113 } 114 return conn, nil 115 }