Skip to content

Commit 4caed31

Browse files
committed
refactor: mv params parse and valid part to pkg package that client and daemon can both use
Signed-off-by: Michael Wan <[email protected]>
1 parent eb8484d commit 4caed31

31 files changed

+1302
-846
lines changed

cli/container.go

Lines changed: 32 additions & 279 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
package main
22

33
import (
4-
"fmt"
5-
"net"
6-
"strconv"
74
"strings"
85

96
"github.com/alibaba/pouch/apis/types"
10-
"github.com/alibaba/pouch/pkg/runconfig"
11-
"github.com/docker/go-connections/nat"
7+
"github.com/alibaba/pouch/pkg/opts"
128

13-
units "github.com/docker/go-units"
149
strfmt "github.com/go-openapi/strfmt"
1510
)
1611

@@ -73,125 +68,86 @@ type container struct {
7368
}
7469

7570
func (c *container) config() (*types.ContainerCreateConfig, error) {
76-
labels, err := parseLabels(c.labels)
71+
labels, err := opts.ParseLabels(c.labels)
7772
if err != nil {
7873
return nil, err
7974
}
8075

81-
if err := validateMemorySwappiness(c.memorySwappiness); err != nil {
76+
if err := opts.ValidateMemorySwappiness(c.memorySwappiness); err != nil {
8277
return nil, err
8378
}
8479

85-
memory, err := parseMemory(c.memory)
80+
memory, err := opts.ParseMemory(c.memory)
8681
if err != nil {
8782
return nil, err
8883
}
8984

90-
memorySwap, err := parseMemorySwap(c.memorySwap)
85+
memorySwap, err := opts.ParseMemorySwap(c.memorySwap)
9186
if err != nil {
9287
return nil, err
9388
}
9489

95-
intelRdtL3Cbm, err := parseIntelRdt(c.IntelRdtL3Cbm)
90+
intelRdtL3Cbm, err := opts.ParseIntelRdt(c.IntelRdtL3Cbm)
9691
if err != nil {
9792
return nil, err
9893
}
9994

100-
deviceMappings, err := parseDeviceMappings(c.devices)
95+
deviceMappings, err := opts.ParseDeviceMappings(c.devices)
10196
if err != nil {
10297
return nil, err
10398
}
10499

105-
restartPolicy, err := parseRestartPolicy(c.restartPolicy)
100+
restartPolicy, err := opts.ParseRestartPolicy(c.restartPolicy)
106101
if err != nil {
107102
return nil, err
108103
}
109104

110-
sysctls, err := parseSysctls(c.sysctls)
111-
if err != nil {
105+
if err := opts.ValidateRestartPolicy(restartPolicy); err != nil {
112106
return nil, err
113107
}
114108

115-
diskQuota, err := parseDiskQuota(c.diskQuota)
109+
sysctls, err := opts.ParseSysctls(c.sysctls)
116110
if err != nil {
117111
return nil, err
118112
}
119113

120-
if err := validateOOMScore(c.oomScoreAdj); err != nil {
114+
diskQuota, err := opts.ParseDiskQuota(c.diskQuota)
115+
if err != nil {
121116
return nil, err
122117
}
123118

124-
var networkMode string
125-
if len(c.networks) == 0 {
126-
networkMode = "bridge"
127-
}
128-
networkingConfig := &types.NetworkingConfig{
129-
EndpointsConfig: map[string]*types.EndpointSettings{},
119+
if err := opts.ValidateDiskQuota(diskQuota); err != nil {
120+
return nil, err
130121
}
131-
for _, network := range c.networks {
132-
name, parameter, mode, err := parseNetwork(network)
133-
if err != nil {
134-
return nil, err
135-
}
136-
137-
if networkMode == "" || mode == "mode" {
138-
networkMode = name
139-
}
140122

141-
if name == "container" {
142-
networkMode = fmt.Sprintf("%s:%s", name, parameter)
143-
} else if ipaddr := net.ParseIP(parameter); ipaddr != nil {
144-
networkingConfig.EndpointsConfig[name] = &types.EndpointSettings{
145-
IPAddress: parameter,
146-
IPAMConfig: &types.EndpointIPAMConfig{
147-
IPV4Address: parameter,
148-
},
149-
}
150-
}
123+
if err := opts.ValidateOOMScore(c.oomScoreAdj); err != nil {
124+
return nil, err
151125
}
152126

153-
// parse port binding
154-
tmpPorts, tmpPortBindings, err := nat.ParsePortSpecs(c.ports)
127+
networkingConfig, networkMode, err := opts.ParseNetworks(c.networks)
155128
if err != nil {
156129
return nil, err
157130
}
158-
// translate ports and portbingings
159-
ports := map[string]interface{}{}
160-
for n, p := range tmpPorts {
161-
ports[string(n)] = p
131+
132+
if err := opts.ValidateNetworks(networkingConfig); err != nil {
133+
return nil, err
162134
}
163-
portBindings := make(types.PortMap)
164-
for n, pbs := range tmpPortBindings {
165-
portBindings[string(n)] = []types.PortBinding{}
166-
for _, tmpPb := range pbs {
167-
pb := types.PortBinding{HostIP: tmpPb.HostIP, HostPort: tmpPb.HostPort}
168-
portBindings[string(n)] = append(portBindings[string(n)], pb)
169-
}
135+
136+
portBindings, err := opts.ParsePortBinding(c.ports)
137+
if err != nil {
138+
return nil, err
170139
}
171140

172-
for _, e := range c.expose {
173-
if strings.Contains(e, ":") {
174-
return nil, fmt.Errorf("invalid port format for --expose: %s", e)
175-
}
141+
// FIXME(ziren): do we need verify portBinding ???
142+
if err := opts.ValidatePortBinding(portBindings); err != nil {
143+
return nil, err
144+
}
176145

177-
//support two formats for expose, original format <portnum>/[<proto>] or <startport-endport>/[<proto>]
178-
proto, port := nat.SplitProtoPort(e)
179-
//parse the start and end port and create a sequence of ports to expose
180-
//if expose a port, the start and end port are the same
181-
start, end, err := nat.ParsePortRange(port)
182-
if err != nil {
183-
return nil, fmt.Errorf("invalid range format for --expose: %s, error: %s", e, err)
184-
}
185-
for i := start; i <= end; i++ {
186-
p, err := nat.NewPort(proto, strconv.FormatUint(i, 10))
187-
if err != nil {
188-
return nil, err
189-
}
190-
if _, exists := ports[string(p)]; !exists {
191-
ports[string(p)] = struct{}{}
192-
}
193-
}
146+
ports, err := opts.ParseExposedPorts(c.ports, c.expose)
147+
if err != nil {
148+
return nil, err
194149
}
150+
195151
config := &types.ContainerCreateConfig{
196152
ContainerConfig: types.ContainerConfig{
197153
Tty: c.tty,
@@ -258,206 +214,3 @@ func (c *container) config() (*types.ContainerCreateConfig, error) {
258214

259215
return config, nil
260216
}
261-
262-
func parseSysctls(sysctls []string) (map[string]string, error) {
263-
results := make(map[string]string)
264-
for _, sysctl := range sysctls {
265-
fields, err := parseSysctl(sysctl)
266-
if err != nil {
267-
return nil, err
268-
}
269-
k, v := fields[0], fields[1]
270-
results[k] = v
271-
}
272-
return results, nil
273-
}
274-
275-
func parseSysctl(sysctl string) ([]string, error) {
276-
fields := strings.SplitN(sysctl, "=", 2)
277-
if len(fields) != 2 {
278-
return nil, fmt.Errorf("invalid sysctl %s: sysctl must be in format of key=value", sysctl)
279-
}
280-
return fields, nil
281-
}
282-
283-
func parseLabels(labels []string) (map[string]string, error) {
284-
results := make(map[string]string)
285-
for _, label := range labels {
286-
fields, err := parseLabel(label)
287-
if err != nil {
288-
return nil, err
289-
}
290-
k, v := fields[0], fields[1]
291-
results[k] = v
292-
}
293-
return results, nil
294-
}
295-
296-
func parseLabel(label string) ([]string, error) {
297-
fields := strings.SplitN(label, "=", 2)
298-
if len(fields) != 2 {
299-
return nil, fmt.Errorf("invalid label %s: label must be in format of key=value", label)
300-
}
301-
return fields, nil
302-
}
303-
304-
func parseDeviceMappings(devices []string) ([]*types.DeviceMapping, error) {
305-
results := []*types.DeviceMapping{}
306-
for _, device := range devices {
307-
deviceMapping, err := parseDevice(device)
308-
if err != nil {
309-
return nil, err
310-
}
311-
results = append(results, deviceMapping)
312-
}
313-
return results, nil
314-
}
315-
316-
func parseDevice(device string) (*types.DeviceMapping, error) {
317-
deviceMapping, err := runconfig.ParseDevice(device)
318-
if err != nil {
319-
return nil, fmt.Errorf("parse devices error: %s", err)
320-
}
321-
if !runconfig.ValidDeviceMode(deviceMapping.CgroupPermissions) {
322-
return nil, fmt.Errorf("%s invalid device mode: %s", device, deviceMapping.CgroupPermissions)
323-
}
324-
return deviceMapping, nil
325-
}
326-
327-
func parseMemory(memory string) (int64, error) {
328-
if memory == "" {
329-
return 0, nil
330-
}
331-
result, err := units.RAMInBytes(memory)
332-
if err != nil {
333-
return 0, err
334-
}
335-
return result, nil
336-
}
337-
338-
func parseMemorySwap(memorySwap string) (int64, error) {
339-
if memorySwap == "" {
340-
return 0, nil
341-
}
342-
if memorySwap == "-1" {
343-
return -1, nil
344-
}
345-
result, err := units.RAMInBytes(memorySwap)
346-
if err != nil {
347-
return 0, err
348-
}
349-
return result, nil
350-
}
351-
352-
func validateMemorySwappiness(memorySwappiness int64) error {
353-
if memorySwappiness != -1 && (memorySwappiness < 0 || memorySwappiness > 100) {
354-
return fmt.Errorf("invalid memory swappiness: %d (its range is -1 or 0-100)", memorySwappiness)
355-
}
356-
return nil
357-
}
358-
359-
func parseIntelRdt(intelRdtL3Cbm string) (string, error) {
360-
// FIXME: add Intel RDT L3 Cbm validation
361-
return intelRdtL3Cbm, nil
362-
}
363-
364-
func parseRestartPolicy(restartPolicy string) (*types.RestartPolicy, error) {
365-
policy := &types.RestartPolicy{}
366-
367-
if restartPolicy == "" {
368-
policy.Name = "no"
369-
return policy, nil
370-
}
371-
372-
fields := strings.Split(restartPolicy, ":")
373-
policy.Name = fields[0]
374-
375-
switch policy.Name {
376-
case "always", "unless-stopped", "no":
377-
case "on-failure":
378-
if len(fields) > 2 {
379-
return nil, fmt.Errorf("invalid restart policy: %s", restartPolicy)
380-
}
381-
if len(fields) == 2 {
382-
n, err := strconv.Atoi(fields[1])
383-
if err != nil {
384-
return nil, fmt.Errorf("invalid restart policy: %v", err)
385-
}
386-
policy.MaximumRetryCount = int64(n)
387-
}
388-
default:
389-
return nil, fmt.Errorf("invalid restart policy: %s", restartPolicy)
390-
}
391-
392-
return policy, nil
393-
}
394-
395-
// network format as below:
396-
// [network]:[ip_address], such as: mynetwork:172.17.0.2 or mynetwork(ip alloc by ipam) or 172.17.0.2(default network is bridge)
397-
// [network_mode]:[parameter], such as: host(use host network) or container:containerID(use exist container network)
398-
// [network_mode]:[parameter]:mode, such as: mynetwork:172.17.0.2:mode(if the container has multi-networks, the network is the default network mode)
399-
func parseNetwork(network string) (string, string, string, error) {
400-
var (
401-
name string
402-
parameter string
403-
mode string
404-
)
405-
if network == "" {
406-
return "", "", "", fmt.Errorf("invalid network: cannot be empty")
407-
}
408-
arr := strings.Split(network, ":")
409-
switch len(arr) {
410-
case 1:
411-
if ipaddr := net.ParseIP(arr[0]); ipaddr != nil {
412-
parameter = arr[0]
413-
} else {
414-
name = arr[0]
415-
}
416-
case 2:
417-
name = arr[0]
418-
if name == "container" {
419-
parameter = arr[1]
420-
} else if ipaddr := net.ParseIP(arr[1]); ipaddr != nil {
421-
parameter = arr[1]
422-
} else {
423-
mode = arr[1]
424-
}
425-
default:
426-
name = arr[0]
427-
parameter = arr[1]
428-
mode = arr[2]
429-
}
430-
431-
return name, parameter, mode, nil
432-
}
433-
434-
func parseDiskQuota(quotas []string) (map[string]string, error) {
435-
var quotaMaps = make(map[string]string)
436-
437-
for _, quota := range quotas {
438-
if quota == "" {
439-
return nil, fmt.Errorf("invalid format for disk quota: %s", quota)
440-
}
441-
442-
parts := strings.Split(quota, "=")
443-
switch len(parts) {
444-
case 1:
445-
quotaMaps["/"] = parts[0]
446-
case 2:
447-
quotaMaps[parts[0]] = parts[1]
448-
default:
449-
return nil, fmt.Errorf("invalid format for disk quota: %s", quota)
450-
}
451-
}
452-
453-
return quotaMaps, nil
454-
}
455-
456-
// validateOOMScore validates oom score
457-
func validateOOMScore(score int64) error {
458-
if score < -1000 || score > 1000 {
459-
return fmt.Errorf("oom-score-adj should be in range [-1000, 1000]")
460-
}
461-
462-
return nil
463-
}

0 commit comments

Comments
 (0)