8e98c98e52
Signed-off-by: Daniel Nephin <dnephin@docker.com>
118 lines
3.2 KiB
Go
118 lines
3.2 KiB
Go
// Package parsers provides helper functions to parse and validate different type
|
|
// of string. It can be hosts, unix addresses, tcp addresses, filters, kernel
|
|
// operating system versions.
|
|
package parsers
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// PartParser parses and validates the specified string (data) using the specified template
|
|
// e.g. ip:public:private -> 192.168.0.1:80:8000
|
|
func PartParser(template, data string) (map[string]string, error) {
|
|
// ip:public:private
|
|
var (
|
|
templateParts = strings.Split(template, ":")
|
|
parts = strings.Split(data, ":")
|
|
out = make(map[string]string, len(templateParts))
|
|
)
|
|
if len(parts) != len(templateParts) {
|
|
return nil, fmt.Errorf("Invalid format to parse. %s should match template %s", data, template)
|
|
}
|
|
|
|
for i, t := range templateParts {
|
|
value := ""
|
|
if len(parts) > i {
|
|
value = parts[i]
|
|
}
|
|
out[t] = value
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// ParseKeyValueOpt parses and validates the specified string as a key/value pair (key=value)
|
|
func ParseKeyValueOpt(opt string) (string, string, error) {
|
|
parts := strings.SplitN(opt, "=", 2)
|
|
if len(parts) != 2 {
|
|
return "", "", fmt.Errorf("Unable to parse key/value option: %s", opt)
|
|
}
|
|
return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]), nil
|
|
}
|
|
|
|
// ParsePortRange parses and validates the specified string as a port-range (8000-9000)
|
|
func ParsePortRange(ports string) (uint64, uint64, error) {
|
|
if ports == "" {
|
|
return 0, 0, fmt.Errorf("Empty string specified for ports.")
|
|
}
|
|
if !strings.Contains(ports, "-") {
|
|
start, err := strconv.ParseUint(ports, 10, 16)
|
|
end := start
|
|
return start, end, err
|
|
}
|
|
|
|
parts := strings.Split(ports, "-")
|
|
start, err := strconv.ParseUint(parts[0], 10, 16)
|
|
if err != nil {
|
|
return 0, 0, err
|
|
}
|
|
end, err := strconv.ParseUint(parts[1], 10, 16)
|
|
if err != nil {
|
|
return 0, 0, err
|
|
}
|
|
if end < start {
|
|
return 0, 0, fmt.Errorf("Invalid range specified for the Port: %s", ports)
|
|
}
|
|
return start, end, nil
|
|
}
|
|
|
|
// ParseUintList parses and validates the specified string as the value
|
|
// found in some cgroup file (e.g. `cpuset.cpus`, `cpuset.mems`), which could be
|
|
// one of the formats below. Note that duplicates are actually allowed in the
|
|
// input string. It returns a `map[int]bool` with available elements from `val`
|
|
// set to `true`.
|
|
// Supported formats:
|
|
// 7
|
|
// 1-6
|
|
// 0,3-4,7,8-10
|
|
// 0-0,0,1-7
|
|
// 03,1-3 <- this is gonna get parsed as [1,2,3]
|
|
// 3,2,1
|
|
// 0-2,3,1
|
|
func ParseUintList(val string) (map[int]bool, error) {
|
|
if val == "" {
|
|
return map[int]bool{}, nil
|
|
}
|
|
|
|
availableInts := make(map[int]bool)
|
|
split := strings.Split(val, ",")
|
|
errInvalidFormat := fmt.Errorf("invalid format: %s", val)
|
|
|
|
for _, r := range split {
|
|
if !strings.Contains(r, "-") {
|
|
v, err := strconv.Atoi(r)
|
|
if err != nil {
|
|
return nil, errInvalidFormat
|
|
}
|
|
availableInts[v] = true
|
|
} else {
|
|
split := strings.SplitN(r, "-", 2)
|
|
min, err := strconv.Atoi(split[0])
|
|
if err != nil {
|
|
return nil, errInvalidFormat
|
|
}
|
|
max, err := strconv.Atoi(split[1])
|
|
if err != nil {
|
|
return nil, errInvalidFormat
|
|
}
|
|
if max < min {
|
|
return nil, errInvalidFormat
|
|
}
|
|
for i := min; i <= max; i++ {
|
|
availableInts[i] = true
|
|
}
|
|
}
|
|
}
|
|
return availableInts, nil
|
|
}
|