Browse code

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>

Vincent Demeester authored on 2017/06/23 23:26:17
Showing 4 changed files
... ...
@@ -4,15 +4,9 @@ import (
4 4
 	"encoding/json"
5 5
 	"encoding/pem"
6 6
 	"fmt"
7
-	"mime"
8 7
 	"os"
9 8
 	"path/filepath"
10
-	"sort"
11
-	"strconv"
12
-	"strings"
13 9
 
14
-	"github.com/Sirupsen/logrus"
15
-	"github.com/docker/docker/api/types"
16 10
 	"github.com/docker/docker/pkg/ioutils"
17 11
 	"github.com/docker/docker/pkg/system"
18 12
 	"github.com/docker/libtrust"
... ...
@@ -28,101 +22,6 @@ const (
28 28
 	NoBaseImageSpecifier string = "scratch"
29 29
 )
30 30
 
31
-// byPortInfo is a temporary type used to sort types.Port by its fields
32
-type byPortInfo []types.Port
33
-
34
-func (r byPortInfo) Len() int      { return len(r) }
35
-func (r byPortInfo) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
36
-func (r byPortInfo) Less(i, j int) bool {
37
-	if r[i].PrivatePort != r[j].PrivatePort {
38
-		return r[i].PrivatePort < r[j].PrivatePort
39
-	}
40
-
41
-	if r[i].IP != r[j].IP {
42
-		return r[i].IP < r[j].IP
43
-	}
44
-
45
-	if r[i].PublicPort != r[j].PublicPort {
46
-		return r[i].PublicPort < r[j].PublicPort
47
-	}
48
-
49
-	return r[i].Type < r[j].Type
50
-}
51
-
52
-// DisplayablePorts returns formatted string representing open ports of container
53
-// e.g. "0.0.0.0:80->9090/tcp, 9988/tcp"
54
-// it's used by command 'docker ps'
55
-func DisplayablePorts(ports []types.Port) string {
56
-	type portGroup struct {
57
-		first uint16
58
-		last  uint16
59
-	}
60
-	groupMap := make(map[string]*portGroup)
61
-	var result []string
62
-	var hostMappings []string
63
-	var groupMapKeys []string
64
-	sort.Sort(byPortInfo(ports))
65
-	for _, port := range ports {
66
-		current := port.PrivatePort
67
-		portKey := port.Type
68
-		if port.IP != "" {
69
-			if port.PublicPort != current {
70
-				hostMappings = append(hostMappings, fmt.Sprintf("%s:%d->%d/%s", port.IP, port.PublicPort, port.PrivatePort, port.Type))
71
-				continue
72
-			}
73
-			portKey = fmt.Sprintf("%s/%s", port.IP, port.Type)
74
-		}
75
-		group := groupMap[portKey]
76
-
77
-		if group == nil {
78
-			groupMap[portKey] = &portGroup{first: current, last: current}
79
-			// record order that groupMap keys are created
80
-			groupMapKeys = append(groupMapKeys, portKey)
81
-			continue
82
-		}
83
-		if current == (group.last + 1) {
84
-			group.last = current
85
-			continue
86
-		}
87
-
88
-		result = append(result, formGroup(portKey, group.first, group.last))
89
-		groupMap[portKey] = &portGroup{first: current, last: current}
90
-	}
91
-	for _, portKey := range groupMapKeys {
92
-		g := groupMap[portKey]
93
-		result = append(result, formGroup(portKey, g.first, g.last))
94
-	}
95
-	result = append(result, hostMappings...)
96
-	return strings.Join(result, ", ")
97
-}
98
-
99
-func formGroup(key string, start, last uint16) string {
100
-	parts := strings.Split(key, "/")
101
-	groupType := parts[0]
102
-	var ip string
103
-	if len(parts) > 1 {
104
-		ip = parts[0]
105
-		groupType = parts[1]
106
-	}
107
-	group := strconv.Itoa(int(start))
108
-	if start != last {
109
-		group = fmt.Sprintf("%s-%d", group, last)
110
-	}
111
-	if ip != "" {
112
-		group = fmt.Sprintf("%s:%s->%s", ip, group, group)
113
-	}
114
-	return fmt.Sprintf("%s/%s", group, groupType)
115
-}
116
-
117
-// MatchesContentType validates the content type against the expected one
118
-func MatchesContentType(contentType, expectedType string) bool {
119
-	mimetype, _, err := mime.ParseMediaType(contentType)
120
-	if err != nil {
121
-		logrus.Errorf("Error parsing media type: %s error: %v", contentType, err)
122
-	}
123
-	return err == nil && mimetype == expectedType
124
-}
125
-
126 31
 // LoadOrCreateTrustKey attempts to load the libtrust key at the given path,
127 32
 // otherwise generates a new one
128 33
 func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) {
... ...
@@ -6,272 +6,8 @@ import (
6 6
 	"testing"
7 7
 
8 8
 	"os"
9
-
10
-	"github.com/docker/docker/api/types"
11 9
 )
12 10
 
13
-type ports struct {
14
-	ports    []types.Port
15
-	expected string
16
-}
17
-
18
-// DisplayablePorts
19
-func TestDisplayablePorts(t *testing.T) {
20
-	cases := []ports{
21
-		{
22
-			[]types.Port{
23
-				{
24
-					PrivatePort: 9988,
25
-					Type:        "tcp",
26
-				},
27
-			},
28
-			"9988/tcp"},
29
-		{
30
-			[]types.Port{
31
-				{
32
-					PrivatePort: 9988,
33
-					Type:        "udp",
34
-				},
35
-			},
36
-			"9988/udp",
37
-		},
38
-		{
39
-			[]types.Port{
40
-				{
41
-					IP:          "0.0.0.0",
42
-					PrivatePort: 9988,
43
-					Type:        "tcp",
44
-				},
45
-			},
46
-			"0.0.0.0:0->9988/tcp",
47
-		},
48
-		{
49
-			[]types.Port{
50
-				{
51
-					PrivatePort: 9988,
52
-					PublicPort:  8899,
53
-					Type:        "tcp",
54
-				},
55
-			},
56
-			"9988/tcp",
57
-		},
58
-		{
59
-			[]types.Port{
60
-				{
61
-					IP:          "4.3.2.1",
62
-					PrivatePort: 9988,
63
-					PublicPort:  8899,
64
-					Type:        "tcp",
65
-				},
66
-			},
67
-			"4.3.2.1:8899->9988/tcp",
68
-		},
69
-		{
70
-			[]types.Port{
71
-				{
72
-					IP:          "4.3.2.1",
73
-					PrivatePort: 9988,
74
-					PublicPort:  9988,
75
-					Type:        "tcp",
76
-				},
77
-			},
78
-			"4.3.2.1:9988->9988/tcp",
79
-		},
80
-		{
81
-			[]types.Port{
82
-				{
83
-					PrivatePort: 9988,
84
-					Type:        "udp",
85
-				}, {
86
-					PrivatePort: 9988,
87
-					Type:        "udp",
88
-				},
89
-			},
90
-			"9988/udp, 9988/udp",
91
-		},
92
-		{
93
-			[]types.Port{
94
-				{
95
-					IP:          "1.2.3.4",
96
-					PublicPort:  9998,
97
-					PrivatePort: 9998,
98
-					Type:        "udp",
99
-				}, {
100
-					IP:          "1.2.3.4",
101
-					PublicPort:  9999,
102
-					PrivatePort: 9999,
103
-					Type:        "udp",
104
-				},
105
-			},
106
-			"1.2.3.4:9998-9999->9998-9999/udp",
107
-		},
108
-		{
109
-			[]types.Port{
110
-				{
111
-					IP:          "1.2.3.4",
112
-					PublicPort:  8887,
113
-					PrivatePort: 9998,
114
-					Type:        "udp",
115
-				}, {
116
-					IP:          "1.2.3.4",
117
-					PublicPort:  8888,
118
-					PrivatePort: 9999,
119
-					Type:        "udp",
120
-				},
121
-			},
122
-			"1.2.3.4:8887->9998/udp, 1.2.3.4:8888->9999/udp",
123
-		},
124
-		{
125
-			[]types.Port{
126
-				{
127
-					PrivatePort: 9998,
128
-					Type:        "udp",
129
-				}, {
130
-					PrivatePort: 9999,
131
-					Type:        "udp",
132
-				},
133
-			},
134
-			"9998-9999/udp",
135
-		},
136
-		{
137
-			[]types.Port{
138
-				{
139
-					IP:          "1.2.3.4",
140
-					PrivatePort: 6677,
141
-					PublicPort:  7766,
142
-					Type:        "tcp",
143
-				}, {
144
-					PrivatePort: 9988,
145
-					PublicPort:  8899,
146
-					Type:        "udp",
147
-				},
148
-			},
149
-			"9988/udp, 1.2.3.4:7766->6677/tcp",
150
-		},
151
-		{
152
-			[]types.Port{
153
-				{
154
-					IP:          "1.2.3.4",
155
-					PrivatePort: 9988,
156
-					PublicPort:  8899,
157
-					Type:        "udp",
158
-				}, {
159
-					IP:          "1.2.3.4",
160
-					PrivatePort: 9988,
161
-					PublicPort:  8899,
162
-					Type:        "tcp",
163
-				}, {
164
-					IP:          "4.3.2.1",
165
-					PrivatePort: 2233,
166
-					PublicPort:  3322,
167
-					Type:        "tcp",
168
-				},
169
-			},
170
-			"4.3.2.1:3322->2233/tcp, 1.2.3.4:8899->9988/tcp, 1.2.3.4:8899->9988/udp",
171
-		},
172
-		{
173
-			[]types.Port{
174
-				{
175
-					PrivatePort: 9988,
176
-					PublicPort:  8899,
177
-					Type:        "udp",
178
-				}, {
179
-					IP:          "1.2.3.4",
180
-					PrivatePort: 6677,
181
-					PublicPort:  7766,
182
-					Type:        "tcp",
183
-				}, {
184
-					IP:          "4.3.2.1",
185
-					PrivatePort: 2233,
186
-					PublicPort:  3322,
187
-					Type:        "tcp",
188
-				},
189
-			},
190
-			"9988/udp, 4.3.2.1:3322->2233/tcp, 1.2.3.4:7766->6677/tcp",
191
-		},
192
-		{
193
-			[]types.Port{
194
-				{
195
-					PrivatePort: 80,
196
-					Type:        "tcp",
197
-				}, {
198
-					PrivatePort: 1024,
199
-					Type:        "tcp",
200
-				}, {
201
-					PrivatePort: 80,
202
-					Type:        "udp",
203
-				}, {
204
-					PrivatePort: 1024,
205
-					Type:        "udp",
206
-				}, {
207
-					IP:          "1.1.1.1",
208
-					PublicPort:  80,
209
-					PrivatePort: 1024,
210
-					Type:        "tcp",
211
-				}, {
212
-					IP:          "1.1.1.1",
213
-					PublicPort:  80,
214
-					PrivatePort: 1024,
215
-					Type:        "udp",
216
-				}, {
217
-					IP:          "1.1.1.1",
218
-					PublicPort:  1024,
219
-					PrivatePort: 80,
220
-					Type:        "tcp",
221
-				}, {
222
-					IP:          "1.1.1.1",
223
-					PublicPort:  1024,
224
-					PrivatePort: 80,
225
-					Type:        "udp",
226
-				}, {
227
-					IP:          "2.1.1.1",
228
-					PublicPort:  80,
229
-					PrivatePort: 1024,
230
-					Type:        "tcp",
231
-				}, {
232
-					IP:          "2.1.1.1",
233
-					PublicPort:  80,
234
-					PrivatePort: 1024,
235
-					Type:        "udp",
236
-				}, {
237
-					IP:          "2.1.1.1",
238
-					PublicPort:  1024,
239
-					PrivatePort: 80,
240
-					Type:        "tcp",
241
-				}, {
242
-					IP:          "2.1.1.1",
243
-					PublicPort:  1024,
244
-					PrivatePort: 80,
245
-					Type:        "udp",
246
-				},
247
-			},
248
-			"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",
249
-		},
250
-	}
251
-
252
-	for _, port := range cases {
253
-		actual := DisplayablePorts(port.ports)
254
-		if port.expected != actual {
255
-			t.Fatalf("Expected %s, got %s.", port.expected, actual)
256
-		}
257
-	}
258
-}
259
-
260
-// MatchesContentType
261
-func TestJsonContentType(t *testing.T) {
262
-	if !MatchesContentType("application/json", "application/json") {
263
-		t.Fail()
264
-	}
265
-
266
-	if !MatchesContentType("application/json; charset=utf-8", "application/json") {
267
-		t.Fail()
268
-	}
269
-
270
-	if MatchesContentType("dockerapplication/json", "application/json") {
271
-		t.Fail()
272
-	}
273
-}
274
-
275 11
 // LoadOrCreateTrustKey
276 12
 func TestLoadOrCreateTrustKeyInvalidKeyFile(t *testing.T) {
277 13
 	tmpKeyFolderPath, err := ioutil.TempDir("", "api-trustkey-test")
... ...
@@ -3,12 +3,12 @@ package httputils
3 3
 import (
4 4
 	"fmt"
5 5
 	"io"
6
+	"mime"
6 7
 	"net/http"
7 8
 	"strings"
8 9
 
10
+	"github.com/Sirupsen/logrus"
9 11
 	"golang.org/x/net/context"
10
-
11
-	"github.com/docker/docker/api"
12 12
 )
13 13
 
14 14
 // APIVersionKey is the client's requested API version.
... ...
@@ -55,7 +55,7 @@ func CheckForJSON(r *http.Request) error {
55 55
 	}
56 56
 
57 57
 	// Otherwise it better be json
58
-	if api.MatchesContentType(ct, "application/json") {
58
+	if matchesContentType(ct, "application/json") {
59 59
 		return nil
60 60
 	}
61 61
 	return fmt.Errorf("Content-Type specified (%s) must be 'application/json'", ct)
... ...
@@ -86,3 +86,12 @@ func VersionFromContext(ctx context.Context) string {
86 86
 
87 87
 	return ""
88 88
 }
89
+
90
+// matchesContentType validates the content type against the expected one
91
+func matchesContentType(contentType, expectedType string) bool {
92
+	mimetype, _, err := mime.ParseMediaType(contentType)
93
+	if err != nil {
94
+		logrus.Errorf("Error parsing media type: %s error: %v", contentType, err)
95
+	}
96
+	return err == nil && mimetype == expectedType
97
+}
89 98
new file mode 100644
... ...
@@ -0,0 +1,18 @@
0
+package httputils
1
+
2
+import "testing"
3
+
4
+// matchesContentType
5
+func TestJsonContentType(t *testing.T) {
6
+	if !matchesContentType("application/json", "application/json") {
7
+		t.Fail()
8
+	}
9
+
10
+	if !matchesContentType("application/json; charset=utf-8", "application/json") {
11
+		t.Fail()
12
+	}
13
+
14
+	if matchesContentType("dockerapplication/json", "application/json") {
15
+		t.Fail()
16
+	}
17
+}