github.com/containerd/Containerd@v1.4.13/pkg/ttrpcutil/client.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 ttrpcutil 18 19 import ( 20 "sync" 21 "time" 22 23 v1 "github.com/containerd/containerd/api/services/ttrpc/events/v1" 24 "github.com/containerd/containerd/pkg/dialer" 25 "github.com/containerd/ttrpc" 26 "github.com/pkg/errors" 27 ) 28 29 const ttrpcDialTimeout = 5 * time.Second 30 31 type ttrpcConnector func() (*ttrpc.Client, error) 32 33 // Client is the client to interact with TTRPC part of containerd server (plugins, events) 34 type Client struct { 35 mu sync.Mutex 36 connector ttrpcConnector 37 client *ttrpc.Client 38 closed bool 39 } 40 41 // NewClient returns a new containerd TTRPC client that is connected to the containerd instance provided by address 42 func NewClient(address string, opts ...ttrpc.ClientOpts) (*Client, error) { 43 connector := func() (*ttrpc.Client, error) { 44 conn, err := dialer.Dialer(address, ttrpcDialTimeout) 45 if err != nil { 46 return nil, errors.Wrap(err, "failed to connect") 47 } 48 49 client := ttrpc.NewClient(conn, opts...) 50 return client, nil 51 } 52 53 return &Client{ 54 connector: connector, 55 }, nil 56 } 57 58 // Reconnect re-establishes the TTRPC connection to the containerd daemon 59 func (c *Client) Reconnect() error { 60 c.mu.Lock() 61 defer c.mu.Unlock() 62 63 if c.connector == nil { 64 return errors.New("unable to reconnect to containerd, no connector available") 65 } 66 67 if c.closed { 68 return errors.New("client is closed") 69 } 70 71 if c.client != nil { 72 if err := c.client.Close(); err != nil { 73 return err 74 } 75 } 76 77 client, err := c.connector() 78 if err != nil { 79 return err 80 } 81 82 c.client = client 83 return nil 84 } 85 86 // EventsService creates an EventsService client 87 func (c *Client) EventsService() (v1.EventsService, error) { 88 client, err := c.Client() 89 if err != nil { 90 return nil, err 91 } 92 return v1.NewEventsClient(client), nil 93 } 94 95 // Client returns the underlying TTRPC client object 96 func (c *Client) Client() (*ttrpc.Client, error) { 97 c.mu.Lock() 98 defer c.mu.Unlock() 99 if c.client == nil { 100 client, err := c.connector() 101 if err != nil { 102 return nil, err 103 } 104 c.client = client 105 } 106 return c.client, nil 107 } 108 109 // Close closes the clients TTRPC connection to containerd 110 func (c *Client) Close() error { 111 c.mu.Lock() 112 defer c.mu.Unlock() 113 114 c.closed = true 115 if c.client != nil { 116 return c.client.Close() 117 } 118 return nil 119 }