Move ttrpc client to pkg/ttrpcutil

Signed-off-by: Maksym Pavlenko <makpav@amazon.com>
This commit is contained in:
Maksym Pavlenko
2019-05-20 16:44:49 -07:00
parent 7b06c9a1ce
commit 7f79fbb245
5 changed files with 22 additions and 22 deletions

105
pkg/ttrpcutil/client.go Normal file
View File

@@ -0,0 +1,105 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ttrpcutil
import (
"sync"
"time"
v1 "github.com/containerd/containerd/api/services/ttrpc/events/v1"
"github.com/containerd/ttrpc"
"github.com/pkg/errors"
)
const ttrpcDialTimeout = 5 * time.Second
type ttrpcConnector func() (*ttrpc.Client, error)
// Client is the client to interact with TTRPC part of containerd server (plugins, events)
type Client struct {
mu sync.Mutex
connector ttrpcConnector
client *ttrpc.Client
closed bool
}
// NewClient returns a new containerd TTRPC client that is connected to the containerd instance provided by address
func NewClient(address string, opts ...ttrpc.ClientOpts) (*Client, error) {
connector := func() (*ttrpc.Client, error) {
conn, err := ttrpcDial(address, ttrpcDialTimeout)
if err != nil {
return nil, errors.Wrap(err, "failed to connect")
}
client := ttrpc.NewClient(conn, opts...)
return client, nil
}
client, err := connector()
if err != nil {
return nil, err
}
return &Client{
connector: connector,
client: client,
}, nil
}
// Reconnect re-establishes the TTRPC connection to the containerd daemon
func (c *Client) Reconnect() error {
c.mu.Lock()
defer c.mu.Unlock()
if c.connector == nil {
return errors.New("unable to reconnect to containerd, no connector available")
}
if c.closed {
return errors.New("client is closed")
}
client, err := c.connector()
if err != nil {
return err
}
c.client = client
return nil
}
// EventsService creates an EventsService client
func (c *Client) EventsService() v1.EventsService {
return v1.NewEventsClient(c.Client())
}
// Client returns the underlying TTRPC client object
func (c *Client) Client() *ttrpc.Client {
c.mu.Lock()
defer c.mu.Unlock()
return c.client
}
// Close closes the clients TTRPC connection to containerd
func (c *Client) Close() error {
c.mu.Lock()
defer c.mu.Unlock()
c.closed = true
return c.client.Close()
}

View File

@@ -0,0 +1,30 @@
// +build !windows
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ttrpcutil
import (
"net"
"strings"
"time"
)
func ttrpcDial(address string, timeout time.Duration) (net.Conn, error) {
address = strings.TrimPrefix(address, "unix://")
return net.DialTimeout("unix", address, timeout)
}

View File

@@ -0,0 +1,60 @@
// +build windows
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ttrpcutil
import (
"net"
"os"
"time"
winio "github.com/Microsoft/go-winio"
"github.com/pkg/errors"
)
func ttrpcDial(address string, timeout time.Duration) (net.Conn, error) {
var c net.Conn
var lastError error
timedOutError := errors.Errorf("timed out waiting for npipe %s", address)
start := time.Now()
for {
remaining := timeout - time.Since(start)
if remaining <= 0 {
lastError = timedOutError
break
}
c, lastError = winio.DialPipe(address, &remaining)
if lastError == nil {
break
}
if !os.IsNotExist(lastError) {
break
}
// There is nobody serving the pipe. We limit the timeout for this case
// to 5 seconds because any shim that would serve this endpoint should
// serve it within 5 seconds. We use the passed in timeout for the
// `DialPipe` timeout if the pipe exists however to give the pipe time
// to `Accept` the connection.
if time.Since(start) >= 5*time.Second {
lastError = timedOutError
break
}
time.Sleep(10 * time.Millisecond)
}
return c, lastError
}