diff options
Diffstat (limited to 'cmd/podman/common/util.go')
-rw-r--r-- | cmd/podman/common/util.go | 274 |
1 files changed, 0 insertions, 274 deletions
diff --git a/cmd/podman/common/util.go b/cmd/podman/common/util.go deleted file mode 100644 index cdfff9d6f..000000000 --- a/cmd/podman/common/util.go +++ /dev/null @@ -1,274 +0,0 @@ -package common - -import ( - "io/ioutil" - "net" - "strconv" - "strings" - - "github.com/containers/podman/v3/libpod/network/types" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" -) - -// ReadPodIDFile reads the specified file and returns its content (i.e., first -// line). -func ReadPodIDFile(path string) (string, error) { - content, err := ioutil.ReadFile(path) - if err != nil { - return "", errors.Wrap(err, "error reading pod ID file") - } - return strings.Split(string(content), "\n")[0], nil -} - -// ReadPodIDFiles reads the specified files and returns their content (i.e., -// first line). -func ReadPodIDFiles(files []string) ([]string, error) { - ids := []string{} - for _, file := range files { - id, err := ReadPodIDFile(file) - if err != nil { - return nil, err - } - ids = append(ids, id) - } - return ids, nil -} - -// ParseFilters transforms one filter format to another and validates input -func ParseFilters(filter []string) (map[string][]string, error) { - // TODO Remove once filter refactor is finished and url.Values done. - filters := map[string][]string{} - for _, f := range filter { - t := strings.SplitN(f, "=", 2) - filters = make(map[string][]string) - if len(t) < 2 { - return map[string][]string{}, errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f) - } - filters[t[0]] = append(filters[t[0]], t[1]) - } - return filters, nil -} - -// createExpose parses user-provided exposed port definitions and converts them -// into SpecGen format. -// TODO: The SpecGen format should really handle ranges more sanely - we could -// be massively inflating what is sent over the wire with a large range. -func createExpose(expose []string) (map[uint16]string, error) { - toReturn := make(map[uint16]string) - - for _, e := range expose { - // Check for protocol - proto := "tcp" - splitProto := strings.Split(e, "/") - if len(splitProto) > 2 { - return nil, errors.Errorf("invalid expose format - protocol can only be specified once") - } else if len(splitProto) == 2 { - proto = splitProto[1] - } - - // Check for a range - start, len, err := parseAndValidateRange(splitProto[0]) - if err != nil { - return nil, err - } - - var index uint16 - for index = 0; index < len; index++ { - portNum := start + index - protocols, ok := toReturn[portNum] - if !ok { - toReturn[portNum] = proto - } else { - newProto := strings.Join(append(strings.Split(protocols, ","), strings.Split(proto, ",")...), ",") - toReturn[portNum] = newProto - } - } - } - - return toReturn, nil -} - -// CreatePortBindings iterates ports mappings into SpecGen format. -func CreatePortBindings(ports []string) ([]types.PortMapping, error) { - // --publish is formatted as follows: - // [[hostip:]hostport[-endPort]:]containerport[-endPort][/protocol] - toReturn := make([]types.PortMapping, 0, len(ports)) - - for _, p := range ports { - var ( - ctrPort string - proto, hostIP, hostPort *string - ) - - splitProto := strings.Split(p, "/") - switch len(splitProto) { - case 1: - // No protocol was provided - case 2: - proto = &(splitProto[1]) - default: - return nil, errors.Errorf("invalid port format - protocol can only be specified once") - } - - remainder := splitProto[0] - haveV6 := false - - // Check for an IPv6 address in brackets - splitV6 := strings.Split(remainder, "]") - switch len(splitV6) { - case 1: - // Do nothing, proceed as before - case 2: - // We potentially have an IPv6 address - haveV6 = true - if !strings.HasPrefix(splitV6[0], "[") { - return nil, errors.Errorf("invalid port format - IPv6 addresses must be enclosed by []") - } - if !strings.HasPrefix(splitV6[1], ":") { - return nil, errors.Errorf("invalid port format - IPv6 address must be followed by a colon (':')") - } - ipNoPrefix := strings.TrimPrefix(splitV6[0], "[") - hostIP = &ipNoPrefix - remainder = strings.TrimPrefix(splitV6[1], ":") - default: - return nil, errors.Errorf("invalid port format - at most one IPv6 address can be specified in a --publish") - } - - splitPort := strings.Split(remainder, ":") - switch len(splitPort) { - case 1: - if haveV6 { - return nil, errors.Errorf("invalid port format - must provide host and destination port if specifying an IP") - } - ctrPort = splitPort[0] - case 2: - hostPort = &(splitPort[0]) - ctrPort = splitPort[1] - case 3: - if haveV6 { - return nil, errors.Errorf("invalid port format - when v6 address specified, must be [ipv6]:hostPort:ctrPort") - } - hostIP = &(splitPort[0]) - hostPort = &(splitPort[1]) - ctrPort = splitPort[2] - default: - return nil, errors.Errorf("invalid port format - format is [[hostIP:]hostPort:]containerPort") - } - - newPort, err := parseSplitPort(hostIP, hostPort, ctrPort, proto) - if err != nil { - return nil, err - } - - toReturn = append(toReturn, newPort) - } - - return toReturn, nil -} - -// parseSplitPort parses individual components of the --publish flag to produce -// a single port mapping in SpecGen format. -func parseSplitPort(hostIP, hostPort *string, ctrPort string, protocol *string) (types.PortMapping, error) { - newPort := types.PortMapping{} - if ctrPort == "" { - return newPort, errors.Errorf("must provide a non-empty container port to publish") - } - ctrStart, ctrLen, err := parseAndValidateRange(ctrPort) - if err != nil { - return newPort, errors.Wrapf(err, "error parsing container port") - } - newPort.ContainerPort = ctrStart - newPort.Range = ctrLen - - if protocol != nil { - if *protocol == "" { - return newPort, errors.Errorf("must provide a non-empty protocol to publish") - } - newPort.Protocol = *protocol - } - if hostIP != nil { - if *hostIP == "" { - return newPort, errors.Errorf("must provide a non-empty container host IP to publish") - } else if *hostIP != "0.0.0.0" { - // If hostIP is 0.0.0.0, leave it unset - CNI treats - // 0.0.0.0 and empty differently, Docker does not. - testIP := net.ParseIP(*hostIP) - if testIP == nil { - return newPort, errors.Errorf("cannot parse %q as an IP address", *hostIP) - } - newPort.HostIP = testIP.String() - } - } - if hostPort != nil { - if *hostPort == "" { - // Set 0 as a placeholder. The server side of Specgen - // will find a random, open, unused port to use. - newPort.HostPort = 0 - } else { - hostStart, hostLen, err := parseAndValidateRange(*hostPort) - if err != nil { - return newPort, errors.Wrapf(err, "error parsing host port") - } - if hostLen != ctrLen { - return newPort, errors.Errorf("host and container port ranges have different lengths: %d vs %d", hostLen, ctrLen) - } - newPort.HostPort = hostStart - } - } - - hport := newPort.HostPort - logrus.Debugf("Adding port mapping from %d to %d length %d protocol %q", hport, newPort.ContainerPort, newPort.Range, newPort.Protocol) - - return newPort, nil -} - -// Parse and validate a port range. -// Returns start port, length of range, error. -func parseAndValidateRange(portRange string) (uint16, uint16, error) { - splitRange := strings.Split(portRange, "-") - if len(splitRange) > 2 { - return 0, 0, errors.Errorf("invalid port format - port ranges are formatted as startPort-stopPort") - } - - if splitRange[0] == "" { - return 0, 0, errors.Errorf("port numbers cannot be negative") - } - - startPort, err := parseAndValidatePort(splitRange[0]) - if err != nil { - return 0, 0, err - } - - var rangeLen uint16 = 1 - if len(splitRange) == 2 { - if splitRange[1] == "" { - return 0, 0, errors.Errorf("must provide ending number for port range") - } - endPort, err := parseAndValidatePort(splitRange[1]) - if err != nil { - return 0, 0, err - } - if endPort <= startPort { - return 0, 0, errors.Errorf("the end port of a range must be higher than the start port - %d is not higher than %d", endPort, startPort) - } - // Our range is the total number of ports - // involved, so we need to add 1 (8080:8081 is - // 2 ports, for example, not 1) - rangeLen = endPort - startPort + 1 - } - - return startPort, rangeLen, nil -} - -// Turn a single string into a valid U16 port. -func parseAndValidatePort(port string) (uint16, error) { - num, err := strconv.Atoi(port) - if err != nil { - return 0, errors.Wrapf(err, "invalid port number") - } - if num < 1 || num > 65535 { - return 0, errors.Errorf("port numbers must be between 1 and 65535 (inclusive), got %d", num) - } - return uint16(num), nil -} |