[mqtt] Implements mqtt publish tooling
This commit is contained in:
		
							
								
								
									
										242
									
								
								vendor/github.com/docker/go-connections/nat/nat.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										242
									
								
								vendor/github.com/docker/go-connections/nat/nat.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,242 @@
 | 
			
		||||
// Package nat is a convenience package for manipulation of strings describing network ports.
 | 
			
		||||
package nat
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// portSpecTemplate is the expected format for port specifications
 | 
			
		||||
	portSpecTemplate = "ip:hostPort:containerPort"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// PortBinding represents a binding between a Host IP address and a Host Port
 | 
			
		||||
type PortBinding struct {
 | 
			
		||||
	// HostIP is the host IP Address
 | 
			
		||||
	HostIP string `json:"HostIp"`
 | 
			
		||||
	// HostPort is the host port number
 | 
			
		||||
	HostPort string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PortMap is a collection of PortBinding indexed by Port
 | 
			
		||||
type PortMap map[Port][]PortBinding
 | 
			
		||||
 | 
			
		||||
// PortSet is a collection of structs indexed by Port
 | 
			
		||||
type PortSet map[Port]struct{}
 | 
			
		||||
 | 
			
		||||
// Port is a string containing port number and protocol in the format "80/tcp"
 | 
			
		||||
type Port string
 | 
			
		||||
 | 
			
		||||
// NewPort creates a new instance of a Port given a protocol and port number or port range
 | 
			
		||||
func NewPort(proto, port string) (Port, error) {
 | 
			
		||||
	// Check for parsing issues on "port" now so we can avoid having
 | 
			
		||||
	// to check it later on.
 | 
			
		||||
 | 
			
		||||
	portStartInt, portEndInt, err := ParsePortRangeToInt(port)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if portStartInt == portEndInt {
 | 
			
		||||
		return Port(fmt.Sprintf("%d/%s", portStartInt, proto)), nil
 | 
			
		||||
	}
 | 
			
		||||
	return Port(fmt.Sprintf("%d-%d/%s", portStartInt, portEndInt, proto)), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParsePort parses the port number string and returns an int
 | 
			
		||||
func ParsePort(rawPort string) (int, error) {
 | 
			
		||||
	if len(rawPort) == 0 {
 | 
			
		||||
		return 0, nil
 | 
			
		||||
	}
 | 
			
		||||
	port, err := strconv.ParseUint(rawPort, 10, 16)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	return int(port), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParsePortRangeToInt parses the port range string and returns start/end ints
 | 
			
		||||
func ParsePortRangeToInt(rawPort string) (int, int, error) {
 | 
			
		||||
	if len(rawPort) == 0 {
 | 
			
		||||
		return 0, 0, nil
 | 
			
		||||
	}
 | 
			
		||||
	start, end, err := ParsePortRange(rawPort)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, 0, err
 | 
			
		||||
	}
 | 
			
		||||
	return int(start), int(end), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Proto returns the protocol of a Port
 | 
			
		||||
func (p Port) Proto() string {
 | 
			
		||||
	proto, _ := SplitProtoPort(string(p))
 | 
			
		||||
	return proto
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Port returns the port number of a Port
 | 
			
		||||
func (p Port) Port() string {
 | 
			
		||||
	_, port := SplitProtoPort(string(p))
 | 
			
		||||
	return port
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Int returns the port number of a Port as an int
 | 
			
		||||
func (p Port) Int() int {
 | 
			
		||||
	portStr := p.Port()
 | 
			
		||||
	// We don't need to check for an error because we're going to
 | 
			
		||||
	// assume that any error would have been found, and reported, in NewPort()
 | 
			
		||||
	port, _ := ParsePort(portStr)
 | 
			
		||||
	return port
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Range returns the start/end port numbers of a Port range as ints
 | 
			
		||||
func (p Port) Range() (int, int, error) {
 | 
			
		||||
	return ParsePortRangeToInt(p.Port())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SplitProtoPort splits a port in the format of proto/port
 | 
			
		||||
func SplitProtoPort(rawPort string) (string, string) {
 | 
			
		||||
	parts := strings.Split(rawPort, "/")
 | 
			
		||||
	l := len(parts)
 | 
			
		||||
	if len(rawPort) == 0 || l == 0 || len(parts[0]) == 0 {
 | 
			
		||||
		return "", ""
 | 
			
		||||
	}
 | 
			
		||||
	if l == 1 {
 | 
			
		||||
		return "tcp", rawPort
 | 
			
		||||
	}
 | 
			
		||||
	if len(parts[1]) == 0 {
 | 
			
		||||
		return "tcp", parts[0]
 | 
			
		||||
	}
 | 
			
		||||
	return parts[1], parts[0]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validateProto(proto string) bool {
 | 
			
		||||
	for _, availableProto := range []string{"tcp", "udp", "sctp"} {
 | 
			
		||||
		if availableProto == proto {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParsePortSpecs receives port specs in the format of ip:public:private/proto and parses
 | 
			
		||||
// these in to the internal types
 | 
			
		||||
func ParsePortSpecs(ports []string) (map[Port]struct{}, map[Port][]PortBinding, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		exposedPorts = make(map[Port]struct{}, len(ports))
 | 
			
		||||
		bindings     = make(map[Port][]PortBinding)
 | 
			
		||||
	)
 | 
			
		||||
	for _, rawPort := range ports {
 | 
			
		||||
		portMappings, err := ParsePortSpec(rawPort)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, portMapping := range portMappings {
 | 
			
		||||
			port := portMapping.Port
 | 
			
		||||
			if _, exists := exposedPorts[port]; !exists {
 | 
			
		||||
				exposedPorts[port] = struct{}{}
 | 
			
		||||
			}
 | 
			
		||||
			bslice, exists := bindings[port]
 | 
			
		||||
			if !exists {
 | 
			
		||||
				bslice = []PortBinding{}
 | 
			
		||||
			}
 | 
			
		||||
			bindings[port] = append(bslice, portMapping.Binding)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return exposedPorts, bindings, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PortMapping is a data object mapping a Port to a PortBinding
 | 
			
		||||
type PortMapping struct {
 | 
			
		||||
	Port    Port
 | 
			
		||||
	Binding PortBinding
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func splitParts(rawport string) (string, string, string) {
 | 
			
		||||
	parts := strings.Split(rawport, ":")
 | 
			
		||||
	n := len(parts)
 | 
			
		||||
	containerport := parts[n-1]
 | 
			
		||||
 | 
			
		||||
	switch n {
 | 
			
		||||
	case 1:
 | 
			
		||||
		return "", "", containerport
 | 
			
		||||
	case 2:
 | 
			
		||||
		return "", parts[0], containerport
 | 
			
		||||
	case 3:
 | 
			
		||||
		return parts[0], parts[1], containerport
 | 
			
		||||
	default:
 | 
			
		||||
		return strings.Join(parts[:n-2], ":"), parts[n-2], containerport
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParsePortSpec parses a port specification string into a slice of PortMappings
 | 
			
		||||
func ParsePortSpec(rawPort string) ([]PortMapping, error) {
 | 
			
		||||
	var proto string
 | 
			
		||||
	rawIP, hostPort, containerPort := splitParts(rawPort)
 | 
			
		||||
	proto, containerPort = SplitProtoPort(containerPort)
 | 
			
		||||
 | 
			
		||||
	// Strip [] from IPV6 addresses
 | 
			
		||||
	ip, _, err := net.SplitHostPort(rawIP + ":")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("Invalid ip address %v: %s", rawIP, err)
 | 
			
		||||
	}
 | 
			
		||||
	if ip != "" && net.ParseIP(ip) == nil {
 | 
			
		||||
		return nil, fmt.Errorf("Invalid ip address: %s", ip)
 | 
			
		||||
	}
 | 
			
		||||
	if containerPort == "" {
 | 
			
		||||
		return nil, fmt.Errorf("No port specified: %s<empty>", rawPort)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	startPort, endPort, err := ParsePortRange(containerPort)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("Invalid containerPort: %s", containerPort)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var startHostPort, endHostPort uint64 = 0, 0
 | 
			
		||||
	if len(hostPort) > 0 {
 | 
			
		||||
		startHostPort, endHostPort, err = ParsePortRange(hostPort)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("Invalid hostPort: %s", hostPort)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if hostPort != "" && (endPort-startPort) != (endHostPort-startHostPort) {
 | 
			
		||||
		// Allow host port range iff containerPort is not a range.
 | 
			
		||||
		// In this case, use the host port range as the dynamic
 | 
			
		||||
		// host port range to allocate into.
 | 
			
		||||
		if endPort != startPort {
 | 
			
		||||
			return nil, fmt.Errorf("Invalid ranges specified for container and host Ports: %s and %s", containerPort, hostPort)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !validateProto(strings.ToLower(proto)) {
 | 
			
		||||
		return nil, fmt.Errorf("Invalid proto: %s", proto)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ports := []PortMapping{}
 | 
			
		||||
	for i := uint64(0); i <= (endPort - startPort); i++ {
 | 
			
		||||
		containerPort = strconv.FormatUint(startPort+i, 10)
 | 
			
		||||
		if len(hostPort) > 0 {
 | 
			
		||||
			hostPort = strconv.FormatUint(startHostPort+i, 10)
 | 
			
		||||
		}
 | 
			
		||||
		// Set hostPort to a range only if there is a single container port
 | 
			
		||||
		// and a dynamic host port.
 | 
			
		||||
		if startPort == endPort && startHostPort != endHostPort {
 | 
			
		||||
			hostPort = fmt.Sprintf("%s-%s", hostPort, strconv.FormatUint(endHostPort, 10))
 | 
			
		||||
		}
 | 
			
		||||
		port, err := NewPort(strings.ToLower(proto), containerPort)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		binding := PortBinding{
 | 
			
		||||
			HostIP:   ip,
 | 
			
		||||
			HostPort: hostPort,
 | 
			
		||||
		}
 | 
			
		||||
		ports = append(ports, PortMapping{Port: port, Binding: binding})
 | 
			
		||||
	}
 | 
			
		||||
	return ports, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										57
									
								
								vendor/github.com/docker/go-connections/nat/parse.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								vendor/github.com/docker/go-connections/nat/parse.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
package nat
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
// DEPRECATED: do not use, this function may be removed in a future version
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										96
									
								
								vendor/github.com/docker/go-connections/nat/sort.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								vendor/github.com/docker/go-connections/nat/sort.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
			
		||||
package nat
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type portSorter struct {
 | 
			
		||||
	ports []Port
 | 
			
		||||
	by    func(i, j Port) bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *portSorter) Len() int {
 | 
			
		||||
	return len(s.ports)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *portSorter) Swap(i, j int) {
 | 
			
		||||
	s.ports[i], s.ports[j] = s.ports[j], s.ports[i]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *portSorter) Less(i, j int) bool {
 | 
			
		||||
	ip := s.ports[i]
 | 
			
		||||
	jp := s.ports[j]
 | 
			
		||||
 | 
			
		||||
	return s.by(ip, jp)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sort sorts a list of ports using the provided predicate
 | 
			
		||||
// This function should compare `i` and `j`, returning true if `i` is
 | 
			
		||||
// considered to be less than `j`
 | 
			
		||||
func Sort(ports []Port, predicate func(i, j Port) bool) {
 | 
			
		||||
	s := &portSorter{ports, predicate}
 | 
			
		||||
	sort.Sort(s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type portMapEntry struct {
 | 
			
		||||
	port    Port
 | 
			
		||||
	binding PortBinding
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type portMapSorter []portMapEntry
 | 
			
		||||
 | 
			
		||||
func (s portMapSorter) Len() int      { return len(s) }
 | 
			
		||||
func (s portMapSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
 | 
			
		||||
 | 
			
		||||
// sort the port so that the order is:
 | 
			
		||||
// 1. port with larger specified bindings
 | 
			
		||||
// 2. larger port
 | 
			
		||||
// 3. port with tcp protocol
 | 
			
		||||
func (s portMapSorter) Less(i, j int) bool {
 | 
			
		||||
	pi, pj := s[i].port, s[j].port
 | 
			
		||||
	hpi, hpj := toInt(s[i].binding.HostPort), toInt(s[j].binding.HostPort)
 | 
			
		||||
	return hpi > hpj || pi.Int() > pj.Int() || (pi.Int() == pj.Int() && strings.ToLower(pi.Proto()) == "tcp")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SortPortMap sorts the list of ports and their respected mapping. The ports
 | 
			
		||||
// will explicit HostPort will be placed first.
 | 
			
		||||
func SortPortMap(ports []Port, bindings PortMap) {
 | 
			
		||||
	s := portMapSorter{}
 | 
			
		||||
	for _, p := range ports {
 | 
			
		||||
		if binding, ok := bindings[p]; ok {
 | 
			
		||||
			for _, b := range binding {
 | 
			
		||||
				s = append(s, portMapEntry{port: p, binding: b})
 | 
			
		||||
			}
 | 
			
		||||
			bindings[p] = []PortBinding{}
 | 
			
		||||
		} else {
 | 
			
		||||
			s = append(s, portMapEntry{port: p})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sort.Sort(s)
 | 
			
		||||
	var (
 | 
			
		||||
		i  int
 | 
			
		||||
		pm = make(map[Port]struct{})
 | 
			
		||||
	)
 | 
			
		||||
	// reorder ports
 | 
			
		||||
	for _, entry := range s {
 | 
			
		||||
		if _, ok := pm[entry.port]; !ok {
 | 
			
		||||
			ports[i] = entry.port
 | 
			
		||||
			pm[entry.port] = struct{}{}
 | 
			
		||||
			i++
 | 
			
		||||
		}
 | 
			
		||||
		// reorder bindings for this port
 | 
			
		||||
		if _, ok := bindings[entry.port]; ok {
 | 
			
		||||
			bindings[entry.port] = append(bindings[entry.port], entry.binding)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func toInt(s string) uint64 {
 | 
			
		||||
	i, _, err := ParsePortRange(s)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		i = 0
 | 
			
		||||
	}
 | 
			
		||||
	return i
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user