github.com/rsampaio/docker@v0.7.2-0.20150827203920-fdc73cc3fc31/pkg/parsers/parsers.go (about) 1 // Package parsers provides helper functions to parse and validate different type 2 // of string. It can be hosts, unix addresses, tcp addresses, filters, kernel 3 // operating system versions. 4 package parsers 5 6 import ( 7 "fmt" 8 "net/url" 9 "path" 10 "runtime" 11 "strconv" 12 "strings" 13 ) 14 15 // ParseHost parses the specified address and returns an address that will be used as the host. 16 // Depending of the address specified, will use the defaultTCPAddr or defaultUnixAddr 17 func ParseHost(defaultTCPAddr, defaultUnixAddr, addr string) (string, error) { 18 addr = strings.TrimSpace(addr) 19 if addr == "" { 20 if runtime.GOOS != "windows" { 21 addr = fmt.Sprintf("unix://%s", defaultUnixAddr) 22 } else { 23 // Note - defaultTCPAddr already includes tcp:// prefix 24 addr = defaultTCPAddr 25 } 26 } 27 addrParts := strings.Split(addr, "://") 28 if len(addrParts) == 1 { 29 addrParts = []string{"tcp", addrParts[0]} 30 } 31 32 switch addrParts[0] { 33 case "tcp": 34 return ParseTCPAddr(addrParts[1], defaultTCPAddr) 35 case "unix": 36 return ParseUnixAddr(addrParts[1], defaultUnixAddr) 37 case "fd": 38 return addr, nil 39 default: 40 return "", fmt.Errorf("Invalid bind address format: %s", addr) 41 } 42 } 43 44 // ParseUnixAddr parses and validates that the specified address is a valid UNIX 45 // socket address. It returns a formatted UNIX socket address, either using the 46 // address parsed from addr, or the contents of defaultAddr if addr is a blank 47 // string. 48 func ParseUnixAddr(addr string, defaultAddr string) (string, error) { 49 addr = strings.TrimPrefix(addr, "unix://") 50 if strings.Contains(addr, "://") { 51 return "", fmt.Errorf("Invalid proto, expected unix: %s", addr) 52 } 53 if addr == "" { 54 addr = defaultAddr 55 } 56 return fmt.Sprintf("unix://%s", addr), nil 57 } 58 59 // ParseTCPAddr parses and validates that the specified address is a valid TCP 60 // address. It returns a formatted TCP address, either using the address parsed 61 // from addr, or the contents of defaultAddr if addr is a blank string. 62 func ParseTCPAddr(addr string, defaultAddr string) (string, error) { 63 addr = strings.TrimPrefix(addr, "tcp://") 64 if strings.Contains(addr, "://") || addr == "" { 65 return "", fmt.Errorf("Invalid proto, expected tcp: %s", addr) 66 } 67 68 u, err := url.Parse("tcp://" + addr) 69 if err != nil { 70 return "", err 71 } 72 hostParts := strings.Split(u.Host, ":") 73 if len(hostParts) != 2 { 74 return "", fmt.Errorf("Invalid bind address format: %s", addr) 75 } 76 host := hostParts[0] 77 if host == "" { 78 host = defaultAddr 79 } 80 81 p, err := strconv.Atoi(hostParts[1]) 82 if err != nil && p == 0 { 83 return "", fmt.Errorf("Invalid bind address format: %s", addr) 84 } 85 return fmt.Sprintf("tcp://%s:%d%s", host, p, u.Path), nil 86 } 87 88 // ParseRepositoryTag gets a repos name and returns the right reposName + tag|digest 89 // The tag can be confusing because of a port in a repository name. 90 // Ex: localhost.localdomain:5000/samalba/hipache:latest 91 // Digest ex: localhost:5000/foo/bar@sha256:bc8813ea7b3603864987522f02a76101c17ad122e1c46d790efc0fca78ca7bfb 92 func ParseRepositoryTag(repos string) (string, string) { 93 n := strings.Index(repos, "@") 94 if n >= 0 { 95 parts := strings.Split(repos, "@") 96 return parts[0], parts[1] 97 } 98 n = strings.LastIndex(repos, ":") 99 if n < 0 { 100 return repos, "" 101 } 102 if tag := repos[n+1:]; !strings.Contains(tag, "/") { 103 return repos[:n], tag 104 } 105 return repos, "" 106 } 107 108 // PartParser parses and validates the specified string (data) using the specified template 109 // e.g. ip:public:private -> 192.168.0.1:80:8000 110 func PartParser(template, data string) (map[string]string, error) { 111 // ip:public:private 112 var ( 113 templateParts = strings.Split(template, ":") 114 parts = strings.Split(data, ":") 115 out = make(map[string]string, len(templateParts)) 116 ) 117 if len(parts) != len(templateParts) { 118 return nil, fmt.Errorf("Invalid format to parse. %s should match template %s", data, template) 119 } 120 121 for i, t := range templateParts { 122 value := "" 123 if len(parts) > i { 124 value = parts[i] 125 } 126 out[t] = value 127 } 128 return out, nil 129 } 130 131 // ParseKeyValueOpt parses and validates the specified string as a key/value pair (key=value) 132 func ParseKeyValueOpt(opt string) (string, string, error) { 133 parts := strings.SplitN(opt, "=", 2) 134 if len(parts) != 2 { 135 return "", "", fmt.Errorf("Unable to parse key/value option: %s", opt) 136 } 137 return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]), nil 138 } 139 140 // ParsePortRange parses and validates the specified string as a port-range (8000-9000) 141 func ParsePortRange(ports string) (uint64, uint64, error) { 142 if ports == "" { 143 return 0, 0, fmt.Errorf("Empty string specified for ports.") 144 } 145 if !strings.Contains(ports, "-") { 146 start, err := strconv.ParseUint(ports, 10, 16) 147 end := start 148 return start, end, err 149 } 150 151 parts := strings.Split(ports, "-") 152 start, err := strconv.ParseUint(parts[0], 10, 16) 153 if err != nil { 154 return 0, 0, err 155 } 156 end, err := strconv.ParseUint(parts[1], 10, 16) 157 if err != nil { 158 return 0, 0, err 159 } 160 if end < start { 161 return 0, 0, fmt.Errorf("Invalid range specified for the Port: %s", ports) 162 } 163 return start, end, nil 164 } 165 166 // ParseLink parses and validates the specified string as a link format (name:alias) 167 func ParseLink(val string) (string, string, error) { 168 if val == "" { 169 return "", "", fmt.Errorf("empty string specified for links") 170 } 171 arr := strings.Split(val, ":") 172 if len(arr) > 2 { 173 return "", "", fmt.Errorf("bad format for links: %s", val) 174 } 175 if len(arr) == 1 { 176 return val, val, nil 177 } 178 // This is kept because we can actually get an HostConfig with links 179 // from an already created container and the format is not `foo:bar` 180 // but `/foo:/c1/bar` 181 if strings.HasPrefix(arr[0], "/") { 182 _, alias := path.Split(arr[1]) 183 return arr[0][1:], alias, nil 184 } 185 return arr[0], arr[1], nil 186 }