Skip to content

Commit

Permalink
feature: add pouch plugin
Browse files Browse the repository at this point in the history
To use existing docker volume and network plugin. We implement pouch plugin
mechanism. We change the plugin discovery directory to /run/pouch/plugins,
/etc/pouch/plugins, /usr/lib/pouch/plugins. In future, maybe we will use the
grpc protocol to implement the plugin

Signed-off-by: Eric Li <[email protected]>
  • Loading branch information
shaloulcy committed May 9, 2018
1 parent 4d3ac8b commit b176f4d
Show file tree
Hide file tree
Showing 12 changed files with 965 additions and 139 deletions.
4 changes: 2 additions & 2 deletions apis/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import (
"syscall"

"github.com/alibaba/pouch/apis/plugins"
"github.com/alibaba/pouch/client"
"github.com/alibaba/pouch/daemon/config"
"github.com/alibaba/pouch/daemon/mgr"
"github.com/alibaba/pouch/pkg/httputils"

"github.com/sirupsen/logrus"
)
Expand Down Expand Up @@ -47,7 +47,7 @@ func (s *Server) Start() (err error) {

var tlsConfig *tls.Config
if s.Config.TLS.Key != "" && s.Config.TLS.Cert != "" {
tlsConfig, err = client.GenTLSConfig(s.Config.TLS.Key, s.Config.TLS.Cert, s.Config.TLS.CA)
tlsConfig, err = httputils.GenTLSConfig(s.Config.TLS.Key, s.Config.TLS.Cert, s.Config.TLS.CA)
if err != nil {
return err
}
Expand Down
82 changes: 5 additions & 77 deletions client/client.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
package client

import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net"
"net/http"
"net/url"
"os"
"strings"
"time"

"github.com/alibaba/pouch/pkg/httputils"
)

var (
Expand Down Expand Up @@ -47,14 +45,14 @@ func NewAPIClient(host string, tls TLSConfig) (CommonAPIClient, error) {
host = defaultHost
}

newURL, basePath, addr, err := parseHost(host)
newURL, basePath, addr, err := httputils.ParseHost(host)
if err != nil {
return nil, fmt.Errorf("failed to parse host %s: %v", host, err)
}

tlsConfig := generateTLSConfig(host, tls)

httpCli := newHTTPClient(newURL, tlsConfig)
httpCli := httputils.NewHTTPClient(newURL, tlsConfig, defaultTimeout)

basePath = generateBaseURL(newURL, tls)

Expand All @@ -72,57 +70,11 @@ func NewAPIClient(host string, tls TLSConfig) (CommonAPIClient, error) {
}, nil
}

// parseHost inputs a host address string, and output three type:
// url.URL, basePath and an error
func parseHost(host string) (*url.URL, string, string, error) {
u, err := url.Parse(host)
if err != nil {
return nil, "", "", err
}

var basePath string
switch u.Scheme {
case "unix":
basePath = "http://d"
case "tcp":
basePath = "http://" + u.Host
case "http":
basePath = host
default:
return nil, "", "", fmt.Errorf("not support url scheme %v", u.Scheme)
}

return u, basePath, strings.TrimPrefix(host, u.Scheme+"://"), nil
}

func newHTTPClient(u *url.URL, tlsConfig *tls.Config) *http.Client {
tr := &http.Transport{
TLSClientConfig: tlsConfig,
}

switch u.Scheme {
case "unix":
unixDial := func(ctx context.Context, network, addr string) (net.Conn, error) {
return net.DialTimeout("unix", u.Path, time.Duration(defaultTimeout))
}
tr.DialContext = unixDial
default:
dial := func(ctx context.Context, network, addr string) (net.Conn, error) {
return net.DialTimeout(network, addr, time.Duration(defaultTimeout))
}
tr.DialContext = dial
}

return &http.Client{
Transport: tr,
}
}

// generateTLSConfig configures TLS for API Client.
func generateTLSConfig(host string, tls TLSConfig) *tls.Config {
// init tls config
if tls.Key != "" && tls.Cert != "" && !strings.HasPrefix(host, "unix://") {
tlsCfg, err := GenTLSConfig(tls.Key, tls.Cert, tls.CA)
tlsCfg, err := httputils.GenTLSConfig(tls.Key, tls.Cert, tls.CA)
if err != nil {
fmt.Fprintf(os.Stderr, "fail to parse tls config %v", err)
os.Exit(1)
Expand Down Expand Up @@ -174,27 +126,3 @@ func (client *APIClient) GetAPIPath(path string, query url.Values) string {
func (client *APIClient) UpdateClientVersion(v string) {
client.version = v
}

// GenTLSConfig returns a tls config object according to inputting parameters.
func GenTLSConfig(key, cert, ca string) (*tls.Config, error) {
tlsConfig := &tls.Config{}
tlsCert, err := tls.LoadX509KeyPair(cert, key)
if err != nil {
return nil, fmt.Errorf("failed to read X509 key pair (cert: %q, key: %q): %v", cert, key, err)
}
tlsConfig.Certificates = []tls.Certificate{tlsCert}
if ca == "" {
return tlsConfig, nil
}

cp := x509.NewCertPool()
pem, err := ioutil.ReadFile(ca)
if err != nil {
return nil, fmt.Errorf("failed to read CA certificate %q: %v", ca, err)
}
if !cp.AppendCertsFromPEM(pem) {
return nil, fmt.Errorf("failed to append certificates from PEM file: %q", ca)
}
tlsConfig.ClientCAs = cp
return tlsConfig, nil
}
60 changes: 0 additions & 60 deletions client/client_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package client

import (
"crypto/tls"
"fmt"
"net/url"
"reflect"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -35,36 +33,6 @@ func TestNewAPIClient(t *testing.T) {
}
}

func TestParseHost(t *testing.T) {
assert := assert.New(t)
type parsed struct {
host string
expectError bool
expectBasePath string
expectAddr string
}

parseds := []parsed{
{host: testHost, expectError: false, expectBasePath: "http://d", expectAddr: "/var/run/pouchd.sock"},
{host: "tcp://localhost:1234", expectError: false, expectBasePath: "http://localhost:1234", expectAddr: "localhost:1234"},
{host: "http://localhost:5678", expectError: false, expectBasePath: "http://localhost:5678", expectAddr: "localhost:5678"},
{host: "foo:bar", expectError: true, expectBasePath: "", expectAddr: ""},
{host: "", expectError: true, expectBasePath: "", expectAddr: ""},
}

for _, p := range parseds {
_, basePath, addr, err := parseHost(p.host)
if p.expectError {
assert.Error(err, fmt.Sprintf("test data %v", p.host))
} else {
assert.NoError(err, fmt.Sprintf("test data %v", p.host))
}

assert.Equal(basePath, p.expectBasePath)
assert.Equal(addr, p.expectAddr)
}
}

func Test_generateBaseURL(t *testing.T) {
type args struct {
u *url.URL
Expand All @@ -85,31 +53,3 @@ func Test_generateBaseURL(t *testing.T) {
})
}
}

func TestGenTLSConfig(t *testing.T) {
type args struct {
key string
cert string
ca string
}
tests := []struct {
name string
args args
want *tls.Config
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := GenTLSConfig(tt.args.key, tt.args.cert, tt.args.ca)
if (err != nil) != tt.wantErr {
t.Errorf("GenTLSConfig() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GenTLSConfig() = %v, want %v", got, tt.want)
}
})
}
}
87 changes: 87 additions & 0 deletions pkg/httputils/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package httputils

import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net"
"net/http"
"net/url"
"strings"
"time"
)

// ParseHost inputs a host address string, and output three type:
// url.URL, basePath and an error.
func ParseHost(host string) (*url.URL, string, string, error) {
u, err := url.Parse(host)
if err != nil {
return nil, "", "", err
}

var basePath string
switch u.Scheme {
case "unix":
basePath = "http://d"
case "tcp":
basePath = "http://" + u.Host
case "http":
basePath = host
case "https":
basePath = host
default:
return nil, "", "", fmt.Errorf("not support url scheme %v", u.Scheme)
}

return u, basePath, strings.TrimPrefix(host, u.Scheme+"://"), nil
}

// GenTLSConfig returns a tls config object according to inputting parameters.
func GenTLSConfig(key, cert, ca string) (*tls.Config, error) {
tlsConfig := &tls.Config{}
tlsCert, err := tls.LoadX509KeyPair(cert, key)
if err != nil {
return nil, fmt.Errorf("failed to read X509 key pair (cert: %q, key: %q): %v", cert, key, err)
}
tlsConfig.Certificates = []tls.Certificate{tlsCert}
if ca == "" {
return tlsConfig, nil
}

cp := x509.NewCertPool()
pem, err := ioutil.ReadFile(ca)
if err != nil {
return nil, fmt.Errorf("failed to read CA certificate %q: %v", ca, err)
}
if !cp.AppendCertsFromPEM(pem) {
return nil, fmt.Errorf("failed to append certificates from PEM file: %q", ca)
}
tlsConfig.ClientCAs = cp
return tlsConfig, nil
}

// NewHTTPClient creates a http client using url and tlsconfig
func NewHTTPClient(u *url.URL, tlsConfig *tls.Config, dialTimeout time.Duration) *http.Client {
tr := &http.Transport{
TLSClientConfig: tlsConfig,
}

switch u.Scheme {
case "unix":
unixDial := func(ctx context.Context, network, addr string) (net.Conn, error) {
return net.DialTimeout("unix", u.Path, dialTimeout)
}
tr.DialContext = unixDial
default:
dial := func(ctx context.Context, network, addr string) (net.Conn, error) {
return net.DialTimeout(network, addr, dialTimeout)
}
tr.DialContext = dial
}

return &http.Client{
Transport: tr,
}
}
72 changes: 72 additions & 0 deletions pkg/httputils/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package httputils

import (
"crypto/tls"
"fmt"
"reflect"
"testing"

"github.com/stretchr/testify/assert"
)

var (
testHost = "unix:///var/run/pouchd.sock"
)

func TestParseHost(t *testing.T) {
assert := assert.New(t)
type parsed struct {
host string
expectError bool
expectBasePath string
expectAddr string
}

parseds := []parsed{
{host: testHost, expectError: false, expectBasePath: "http://d", expectAddr: "/var/run/pouchd.sock"},
{host: "tcp://localhost:1234", expectError: false, expectBasePath: "http://localhost:1234", expectAddr: "localhost:1234"},
{host: "http://localhost:5678", expectError: false, expectBasePath: "http://localhost:5678", expectAddr: "localhost:5678"},
{host: "foo:bar", expectError: true, expectBasePath: "", expectAddr: ""},
{host: "", expectError: true, expectBasePath: "", expectAddr: ""},
}

for _, p := range parseds {
_, basePath, addr, err := ParseHost(p.host)
if p.expectError {
assert.Error(err, fmt.Sprintf("test data %v", p.host))
} else {
assert.NoError(err, fmt.Sprintf("test data %v", p.host))
}

assert.Equal(basePath, p.expectBasePath)
assert.Equal(addr, p.expectAddr)
}
}

func TestGenTLSConfig(t *testing.T) {
type args struct {
key string
cert string
ca string
}
tests := []struct {
name string
args args
want *tls.Config
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := GenTLSConfig(tt.args.key, tt.args.cert, tt.args.ca)
if (err != nil) != tt.wantErr {
t.Errorf("GenTLSConfig() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GenTLSConfig() = %v, want %v", got, tt.want)
}
})
}
}
Loading

0 comments on commit b176f4d

Please sign in to comment.