internal/workload/names.go (38 lines of code) (raw):

// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package workload import ( "fmt" "hash/fnv" "strings" cloudsqlapi "github.com/GoogleCloudPlatform/cloud-sql-proxy-operator/internal/api/v1" ) // ContainerPrefix is the name prefix used on containers added to PodSpecs // by this operator. const ContainerPrefix = "csql-" // ContainerName generates a valid name for a corev1.Container object that // implements this cloudsql instance. Names must be 63 characters or fewer and // adhere to the rfc1035/rfc1123 label (DNS_LABEL) format. r.ObjectMeta.Name // already is required to be 63 characters or less because it is a name. Because // we are prepending 'csql-' ContainerPrefix as a marker, the generated name with // the prefix could be longer than 63 characters. func ContainerName(r *cloudsqlapi.AuthProxyWorkload) string { return SafePrefixedName(ContainerPrefix, r.GetNamespace()+"-"+r.GetName()) } // VolumeName generates a unique, valid name for a volume based on the AuthProxyWorkload // name and the Cloud SQL instance name. func VolumeName(r *cloudsqlapi.AuthProxyWorkload, inst *cloudsqlapi.InstanceSpec, mountType string) string { connName := strings.ReplaceAll(strings.ToLower(inst.ConnectionString), ":", "-") return SafePrefixedName(ContainerPrefix, r.GetName()+"-"+mountType+"-"+connName) } // SafePrefixedName adds a prefix to a name and shortens it while preserving its uniqueness // so that it fits the 63 character limit imposed by kubernetes. // Kubernetes names must follow the DNS Label format for all names. // See https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#rfc-1035-label-names // // DO NOT CHANGE THIS ALGORITHM! The names generated by this function are used // to match containers and volumes to configuration. If the names are generated // differently between one version of the operator and the next, the operator // will break. Existing workloads will not be correctly updated. func SafePrefixedName(prefix, instName string) string { const maxNameLen = 63 // maximum character limit for a name containerPrefixLen := len(prefix) if len(instName)+containerPrefixLen > maxNameLen { // string shortener that will still produce a name that is still unique // even though it is truncated. checksum := mustHash([]byte(instName)) hashSuffix := fmt.Sprintf("-%x", checksum) hashSuffixLen := len(hashSuffix) truncateLen := (maxNameLen - hashSuffixLen - containerPrefixLen) / 2 namePrefix := instName[:truncateLen] nameSuffix := instName[len(instName)-truncateLen:] return strings.ToLower(strings.Join( []string{prefix, namePrefix, nameSuffix, hashSuffix}, "")) } return strings.ToLower(prefix + instName) } // mustHash simply returns the checksum for a slice of bytes func mustHash(bytes []byte) uint32 { h := fnv.New32a() i, err := h.Write(bytes) if err != nil || i != len(bytes) { panic(fmt.Errorf("unable to calculate mustHash for bytes %v %v", bytes, err)) } return h.Sum32() }