Little helper to run CNCF's k3s in Docker
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
k3d/cli/util.go

122 lines
3.1 KiB

package run
import (
"fmt"
"math/rand"
"net"
"strconv"
"strings"
"time"
)
type apiPort struct {
Host string
HostIp string
Port string
}
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const (
letterIdxBits = 6 // 6 bits to represent a letter index
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
)
var src = rand.NewSource(time.Now().UnixNano())
// GenerateRandomString thanks to https://stackoverflow.com/a/31832326/6450189
// GenerateRandomString is used to generate a random string that is used as a cluster secret
func GenerateRandomString(n int) string {
sb := strings.Builder{}
sb.Grow(n)
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
if remain == 0 {
cache, remain = src.Int63(), letterIdxMax
}
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
sb.WriteByte(letterBytes[idx])
i--
}
cache >>= letterIdxBits
remain--
}
return sb.String()
}
/*** Cluster Name Validation ***/
const clusterNameMaxSize int = 35
// CheckClusterName ensures that a cluster name is also a valid host name according to RFC 1123.
// We further restrict the length of the cluster name to maximum 'clusterNameMaxSize'
// so that we can construct the host names based on the cluster name, and still stay
// within the 64 characters limit.
func CheckClusterName(name string) error {
if err := ValidateHostname(name); err != nil {
return fmt.Errorf("[ERROR] Invalid cluster name\n%+v", ValidateHostname(name))
}
if len(name) > clusterNameMaxSize {
return fmt.Errorf("[ERROR] Cluster name is too long (%d > %d)", len(name), clusterNameMaxSize)
}
return nil
}
// ValidateHostname ensures that a cluster name is also a valid host name according to RFC 1123.
func ValidateHostname(name string) error {
if len(name) == 0 {
return fmt.Errorf("[ERROR] no name provided")
}
if name[0] == '-' || name[len(name)-1] == '-' {
return fmt.Errorf("[ERROR] Hostname [%s] must not start or end with - (dash)", name)
}
for _, c := range name {
switch {
case '0' <= c && c <= '9':
case 'a' <= c && c <= 'z':
case 'A' <= c && c <= 'Z':
case c == '-':
break
default:
return fmt.Errorf("[ERROR] Hostname [%s] contains characters other than 'Aa-Zz', '0-9' or '-'", name)
}
}
return nil
}
func parseApiPort(portSpec string) (*apiPort, error) {
var port *apiPort
split := strings.Split(portSpec, ":")
if len(split) > 2 {
return nil, fmt.Errorf("api-port format error")
}
if len(split) == 1 {
port = &apiPort{Port: split[0]}
} else {
// Make sure 'host' can be resolved to an IP address
addrs, err := net.LookupHost(split[0])
if err != nil {
return nil, err
}
port = &apiPort{Host: split[0], HostIp: addrs[0], Port: split[1]}
}
// Verify 'port' is an integer and within port ranges
p, err := strconv.Atoi(port.Port)
if err != nil {
return nil, err
}
if p < 0 || p > 65535 {
return nil, fmt.Errorf("ERROR: --api-port port value out of range")
}
return port, nil
}