mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Move some api
package functions away
- DisplayablePorts is a `cli` function, moving to `docker/cli` - Move MatchesContentType to the only package using it, `api/server/httputils` (and remove the deps on logrus for `api` package) Signed-off-by: Vincent Demeester <vincent@sbr.pm>
This commit is contained in:
parent
4f259698b0
commit
565aa41392
4 changed files with 30 additions and 368 deletions
101
api/common.go
101
api/common.go
|
@ -4,15 +4,9 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
"mime"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/docker/api/types"
|
|
||||||
"github.com/docker/docker/pkg/ioutils"
|
"github.com/docker/docker/pkg/ioutils"
|
||||||
"github.com/docker/docker/pkg/system"
|
"github.com/docker/docker/pkg/system"
|
||||||
"github.com/docker/libtrust"
|
"github.com/docker/libtrust"
|
||||||
|
@ -28,101 +22,6 @@ const (
|
||||||
NoBaseImageSpecifier string = "scratch"
|
NoBaseImageSpecifier string = "scratch"
|
||||||
)
|
)
|
||||||
|
|
||||||
// byPortInfo is a temporary type used to sort types.Port by its fields
|
|
||||||
type byPortInfo []types.Port
|
|
||||||
|
|
||||||
func (r byPortInfo) Len() int { return len(r) }
|
|
||||||
func (r byPortInfo) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
|
||||||
func (r byPortInfo) Less(i, j int) bool {
|
|
||||||
if r[i].PrivatePort != r[j].PrivatePort {
|
|
||||||
return r[i].PrivatePort < r[j].PrivatePort
|
|
||||||
}
|
|
||||||
|
|
||||||
if r[i].IP != r[j].IP {
|
|
||||||
return r[i].IP < r[j].IP
|
|
||||||
}
|
|
||||||
|
|
||||||
if r[i].PublicPort != r[j].PublicPort {
|
|
||||||
return r[i].PublicPort < r[j].PublicPort
|
|
||||||
}
|
|
||||||
|
|
||||||
return r[i].Type < r[j].Type
|
|
||||||
}
|
|
||||||
|
|
||||||
// DisplayablePorts returns formatted string representing open ports of container
|
|
||||||
// e.g. "0.0.0.0:80->9090/tcp, 9988/tcp"
|
|
||||||
// it's used by command 'docker ps'
|
|
||||||
func DisplayablePorts(ports []types.Port) string {
|
|
||||||
type portGroup struct {
|
|
||||||
first uint16
|
|
||||||
last uint16
|
|
||||||
}
|
|
||||||
groupMap := make(map[string]*portGroup)
|
|
||||||
var result []string
|
|
||||||
var hostMappings []string
|
|
||||||
var groupMapKeys []string
|
|
||||||
sort.Sort(byPortInfo(ports))
|
|
||||||
for _, port := range ports {
|
|
||||||
current := port.PrivatePort
|
|
||||||
portKey := port.Type
|
|
||||||
if port.IP != "" {
|
|
||||||
if port.PublicPort != current {
|
|
||||||
hostMappings = append(hostMappings, fmt.Sprintf("%s:%d->%d/%s", port.IP, port.PublicPort, port.PrivatePort, port.Type))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
portKey = fmt.Sprintf("%s/%s", port.IP, port.Type)
|
|
||||||
}
|
|
||||||
group := groupMap[portKey]
|
|
||||||
|
|
||||||
if group == nil {
|
|
||||||
groupMap[portKey] = &portGroup{first: current, last: current}
|
|
||||||
// record order that groupMap keys are created
|
|
||||||
groupMapKeys = append(groupMapKeys, portKey)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if current == (group.last + 1) {
|
|
||||||
group.last = current
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
result = append(result, formGroup(portKey, group.first, group.last))
|
|
||||||
groupMap[portKey] = &portGroup{first: current, last: current}
|
|
||||||
}
|
|
||||||
for _, portKey := range groupMapKeys {
|
|
||||||
g := groupMap[portKey]
|
|
||||||
result = append(result, formGroup(portKey, g.first, g.last))
|
|
||||||
}
|
|
||||||
result = append(result, hostMappings...)
|
|
||||||
return strings.Join(result, ", ")
|
|
||||||
}
|
|
||||||
|
|
||||||
func formGroup(key string, start, last uint16) string {
|
|
||||||
parts := strings.Split(key, "/")
|
|
||||||
groupType := parts[0]
|
|
||||||
var ip string
|
|
||||||
if len(parts) > 1 {
|
|
||||||
ip = parts[0]
|
|
||||||
groupType = parts[1]
|
|
||||||
}
|
|
||||||
group := strconv.Itoa(int(start))
|
|
||||||
if start != last {
|
|
||||||
group = fmt.Sprintf("%s-%d", group, last)
|
|
||||||
}
|
|
||||||
if ip != "" {
|
|
||||||
group = fmt.Sprintf("%s:%s->%s", ip, group, group)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s/%s", group, groupType)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MatchesContentType validates the content type against the expected one
|
|
||||||
func MatchesContentType(contentType, expectedType string) bool {
|
|
||||||
mimetype, _, err := mime.ParseMediaType(contentType)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorf("Error parsing media type: %s error: %v", contentType, err)
|
|
||||||
}
|
|
||||||
return err == nil && mimetype == expectedType
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadOrCreateTrustKey attempts to load the libtrust key at the given path,
|
// LoadOrCreateTrustKey attempts to load the libtrust key at the given path,
|
||||||
// otherwise generates a new one
|
// otherwise generates a new one
|
||||||
func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) {
|
func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) {
|
||||||
|
|
|
@ -6,272 +6,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ports struct {
|
|
||||||
ports []types.Port
|
|
||||||
expected string
|
|
||||||
}
|
|
||||||
|
|
||||||
// DisplayablePorts
|
|
||||||
func TestDisplayablePorts(t *testing.T) {
|
|
||||||
cases := []ports{
|
|
||||||
{
|
|
||||||
[]types.Port{
|
|
||||||
{
|
|
||||||
PrivatePort: 9988,
|
|
||||||
Type: "tcp",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"9988/tcp"},
|
|
||||||
{
|
|
||||||
[]types.Port{
|
|
||||||
{
|
|
||||||
PrivatePort: 9988,
|
|
||||||
Type: "udp",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"9988/udp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
[]types.Port{
|
|
||||||
{
|
|
||||||
IP: "0.0.0.0",
|
|
||||||
PrivatePort: 9988,
|
|
||||||
Type: "tcp",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"0.0.0.0:0->9988/tcp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
[]types.Port{
|
|
||||||
{
|
|
||||||
PrivatePort: 9988,
|
|
||||||
PublicPort: 8899,
|
|
||||||
Type: "tcp",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"9988/tcp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
[]types.Port{
|
|
||||||
{
|
|
||||||
IP: "4.3.2.1",
|
|
||||||
PrivatePort: 9988,
|
|
||||||
PublicPort: 8899,
|
|
||||||
Type: "tcp",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"4.3.2.1:8899->9988/tcp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
[]types.Port{
|
|
||||||
{
|
|
||||||
IP: "4.3.2.1",
|
|
||||||
PrivatePort: 9988,
|
|
||||||
PublicPort: 9988,
|
|
||||||
Type: "tcp",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"4.3.2.1:9988->9988/tcp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
[]types.Port{
|
|
||||||
{
|
|
||||||
PrivatePort: 9988,
|
|
||||||
Type: "udp",
|
|
||||||
}, {
|
|
||||||
PrivatePort: 9988,
|
|
||||||
Type: "udp",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"9988/udp, 9988/udp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
[]types.Port{
|
|
||||||
{
|
|
||||||
IP: "1.2.3.4",
|
|
||||||
PublicPort: 9998,
|
|
||||||
PrivatePort: 9998,
|
|
||||||
Type: "udp",
|
|
||||||
}, {
|
|
||||||
IP: "1.2.3.4",
|
|
||||||
PublicPort: 9999,
|
|
||||||
PrivatePort: 9999,
|
|
||||||
Type: "udp",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"1.2.3.4:9998-9999->9998-9999/udp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
[]types.Port{
|
|
||||||
{
|
|
||||||
IP: "1.2.3.4",
|
|
||||||
PublicPort: 8887,
|
|
||||||
PrivatePort: 9998,
|
|
||||||
Type: "udp",
|
|
||||||
}, {
|
|
||||||
IP: "1.2.3.4",
|
|
||||||
PublicPort: 8888,
|
|
||||||
PrivatePort: 9999,
|
|
||||||
Type: "udp",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"1.2.3.4:8887->9998/udp, 1.2.3.4:8888->9999/udp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
[]types.Port{
|
|
||||||
{
|
|
||||||
PrivatePort: 9998,
|
|
||||||
Type: "udp",
|
|
||||||
}, {
|
|
||||||
PrivatePort: 9999,
|
|
||||||
Type: "udp",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"9998-9999/udp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
[]types.Port{
|
|
||||||
{
|
|
||||||
IP: "1.2.3.4",
|
|
||||||
PrivatePort: 6677,
|
|
||||||
PublicPort: 7766,
|
|
||||||
Type: "tcp",
|
|
||||||
}, {
|
|
||||||
PrivatePort: 9988,
|
|
||||||
PublicPort: 8899,
|
|
||||||
Type: "udp",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"9988/udp, 1.2.3.4:7766->6677/tcp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
[]types.Port{
|
|
||||||
{
|
|
||||||
IP: "1.2.3.4",
|
|
||||||
PrivatePort: 9988,
|
|
||||||
PublicPort: 8899,
|
|
||||||
Type: "udp",
|
|
||||||
}, {
|
|
||||||
IP: "1.2.3.4",
|
|
||||||
PrivatePort: 9988,
|
|
||||||
PublicPort: 8899,
|
|
||||||
Type: "tcp",
|
|
||||||
}, {
|
|
||||||
IP: "4.3.2.1",
|
|
||||||
PrivatePort: 2233,
|
|
||||||
PublicPort: 3322,
|
|
||||||
Type: "tcp",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"4.3.2.1:3322->2233/tcp, 1.2.3.4:8899->9988/tcp, 1.2.3.4:8899->9988/udp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
[]types.Port{
|
|
||||||
{
|
|
||||||
PrivatePort: 9988,
|
|
||||||
PublicPort: 8899,
|
|
||||||
Type: "udp",
|
|
||||||
}, {
|
|
||||||
IP: "1.2.3.4",
|
|
||||||
PrivatePort: 6677,
|
|
||||||
PublicPort: 7766,
|
|
||||||
Type: "tcp",
|
|
||||||
}, {
|
|
||||||
IP: "4.3.2.1",
|
|
||||||
PrivatePort: 2233,
|
|
||||||
PublicPort: 3322,
|
|
||||||
Type: "tcp",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"9988/udp, 4.3.2.1:3322->2233/tcp, 1.2.3.4:7766->6677/tcp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
[]types.Port{
|
|
||||||
{
|
|
||||||
PrivatePort: 80,
|
|
||||||
Type: "tcp",
|
|
||||||
}, {
|
|
||||||
PrivatePort: 1024,
|
|
||||||
Type: "tcp",
|
|
||||||
}, {
|
|
||||||
PrivatePort: 80,
|
|
||||||
Type: "udp",
|
|
||||||
}, {
|
|
||||||
PrivatePort: 1024,
|
|
||||||
Type: "udp",
|
|
||||||
}, {
|
|
||||||
IP: "1.1.1.1",
|
|
||||||
PublicPort: 80,
|
|
||||||
PrivatePort: 1024,
|
|
||||||
Type: "tcp",
|
|
||||||
}, {
|
|
||||||
IP: "1.1.1.1",
|
|
||||||
PublicPort: 80,
|
|
||||||
PrivatePort: 1024,
|
|
||||||
Type: "udp",
|
|
||||||
}, {
|
|
||||||
IP: "1.1.1.1",
|
|
||||||
PublicPort: 1024,
|
|
||||||
PrivatePort: 80,
|
|
||||||
Type: "tcp",
|
|
||||||
}, {
|
|
||||||
IP: "1.1.1.1",
|
|
||||||
PublicPort: 1024,
|
|
||||||
PrivatePort: 80,
|
|
||||||
Type: "udp",
|
|
||||||
}, {
|
|
||||||
IP: "2.1.1.1",
|
|
||||||
PublicPort: 80,
|
|
||||||
PrivatePort: 1024,
|
|
||||||
Type: "tcp",
|
|
||||||
}, {
|
|
||||||
IP: "2.1.1.1",
|
|
||||||
PublicPort: 80,
|
|
||||||
PrivatePort: 1024,
|
|
||||||
Type: "udp",
|
|
||||||
}, {
|
|
||||||
IP: "2.1.1.1",
|
|
||||||
PublicPort: 1024,
|
|
||||||
PrivatePort: 80,
|
|
||||||
Type: "tcp",
|
|
||||||
}, {
|
|
||||||
IP: "2.1.1.1",
|
|
||||||
PublicPort: 1024,
|
|
||||||
PrivatePort: 80,
|
|
||||||
Type: "udp",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"80/tcp, 80/udp, 1024/tcp, 1024/udp, 1.1.1.1:1024->80/tcp, 1.1.1.1:1024->80/udp, 2.1.1.1:1024->80/tcp, 2.1.1.1:1024->80/udp, 1.1.1.1:80->1024/tcp, 1.1.1.1:80->1024/udp, 2.1.1.1:80->1024/tcp, 2.1.1.1:80->1024/udp",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, port := range cases {
|
|
||||||
actual := DisplayablePorts(port.ports)
|
|
||||||
if port.expected != actual {
|
|
||||||
t.Fatalf("Expected %s, got %s.", port.expected, actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MatchesContentType
|
|
||||||
func TestJsonContentType(t *testing.T) {
|
|
||||||
if !MatchesContentType("application/json", "application/json") {
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
|
|
||||||
if !MatchesContentType("application/json; charset=utf-8", "application/json") {
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
|
|
||||||
if MatchesContentType("dockerapplication/json", "application/json") {
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadOrCreateTrustKey
|
// LoadOrCreateTrustKey
|
||||||
func TestLoadOrCreateTrustKeyInvalidKeyFile(t *testing.T) {
|
func TestLoadOrCreateTrustKeyInvalidKeyFile(t *testing.T) {
|
||||||
tmpKeyFolderPath, err := ioutil.TempDir("", "api-trustkey-test")
|
tmpKeyFolderPath, err := ioutil.TempDir("", "api-trustkey-test")
|
||||||
|
|
|
@ -3,12 +3,12 @@ package httputils
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"mime"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
"github.com/docker/docker/api"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// APIVersionKey is the client's requested API version.
|
// APIVersionKey is the client's requested API version.
|
||||||
|
@ -55,7 +55,7 @@ func CheckForJSON(r *http.Request) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise it better be json
|
// Otherwise it better be json
|
||||||
if api.MatchesContentType(ct, "application/json") {
|
if matchesContentType(ct, "application/json") {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return fmt.Errorf("Content-Type specified (%s) must be 'application/json'", ct)
|
return fmt.Errorf("Content-Type specified (%s) must be 'application/json'", ct)
|
||||||
|
@ -86,3 +86,12 @@ func VersionFromContext(ctx context.Context) string {
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// matchesContentType validates the content type against the expected one
|
||||||
|
func matchesContentType(contentType, expectedType string) bool {
|
||||||
|
mimetype, _, err := mime.ParseMediaType(contentType)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("Error parsing media type: %s error: %v", contentType, err)
|
||||||
|
}
|
||||||
|
return err == nil && mimetype == expectedType
|
||||||
|
}
|
||||||
|
|
18
api/server/httputils/httputils_test.go
Normal file
18
api/server/httputils/httputils_test.go
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package httputils
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
// matchesContentType
|
||||||
|
func TestJsonContentType(t *testing.T) {
|
||||||
|
if !matchesContentType("application/json", "application/json") {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !matchesContentType("application/json; charset=utf-8", "application/json") {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
if matchesContentType("dockerapplication/json", "application/json") {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue