|
| 1 | +// Copyright 2023 Google LLC |
| 2 | +// |
| 3 | +// Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | +// you may not use this file except in compliance with the License. |
| 5 | +// You may obtain a copy of the License at |
| 6 | +// |
| 7 | +// http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | +// |
| 9 | +// Unless required by applicable law or agreed to in writing, software |
| 10 | +// distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | +// See the License for the specific language governing permissions and |
| 13 | +// limitations under the License. |
| 14 | + |
| 15 | +// DO NOT EDIT: This code is a subset of services_platform/thetis/gateway/core/v1alpha2/common/appnettranslator/gsm/namer.go |
| 16 | +// and should not be modified to maintain functional consistency. |
| 17 | + |
| 18 | +package csmnamer |
| 19 | + |
| 20 | +import ( |
| 21 | + "fmt" |
| 22 | + "strings" |
| 23 | + "unicode" |
| 24 | +) |
| 25 | + |
| 26 | +const ( |
| 27 | + // Length limit for hash created from fields that uniquely identify a GCE resource and |
| 28 | + // appended as a suffix to the resource name |
| 29 | + nHashLen = 12 |
| 30 | + // max length of a GCE resource name. |
| 31 | + resourceNameMaxLen = 63 |
| 32 | + // clusterUIDLen is the length of cluster UID, computed as a hash of ClusterName |
| 33 | + // prefix used for GCE resource names created by GAMMA mesh. |
| 34 | + clusterUIDLen = 4 |
| 35 | + // csmMeshPrefix is the prefix override used in the CSMMesh use cases. |
| 36 | + csmMeshPrefix = "gsmmesh" |
| 37 | +) |
| 38 | + |
| 39 | +type MeshNamer struct { |
| 40 | + ClusterName string |
| 41 | + Location string |
| 42 | +} |
| 43 | + |
| 44 | +func (m *MeshNamer) GenerateMeshId() string { |
| 45 | + return readableResourceName(m.ClusterName, m.Location) |
| 46 | +} |
| 47 | + |
| 48 | +// Returns a readable resource name in the following format |
| 49 | +// {prefix}-{component#0}-{component#1}...-{hash} |
| 50 | +// The length of the returned resource name is guarantee to be within |
| 51 | +// resourceNameLen which is the maximum length of a GCE resource. A component |
| 52 | +// will only be included explicitly in the resource name if it doesn't have an |
| 53 | +// invalid character (any character that is not a letter, digit or '-'). |
| 54 | +// Components in the resource name maybe trimmed to fit the maximum length |
| 55 | +// requirement. {hash} uniquely identifies the component set. |
| 56 | +func readableResourceName(components ...string) string { |
| 57 | + // clusterHash enforces uniqueness of resources of different clusters in |
| 58 | + // the same project. |
| 59 | + clusterHash := Hash(strings.Join(components, ";"), clusterUIDLen) |
| 60 | + prefix := csmMeshPrefix + "-" + clusterHash |
| 61 | + // resourceHash enforces uniqueness of resources of the same cluster. |
| 62 | + resourceHash := Hash(strings.Join(components, ";"), nHashLen) |
| 63 | + // Ideally we explicitly include all components in the GCP resource name, so |
| 64 | + // it's easier to be related to the corresponding k8s resource(s). However, |
| 65 | + // only certain characters are allowed in a GCP resource name(e.g. a common |
| 66 | + // character '.' in hostnames is not allowed in GCP resource name). |
| 67 | + var explicitComponents []string |
| 68 | + for _, c := range components { |
| 69 | + // Only explicitly include a component in GCP resource name if all |
| 70 | + // characters in it are allowed. Omitting a component here is okay since |
| 71 | + // the resourceHash already represents the full component set. |
| 72 | + if allCharAllowedInResourceName(c) { |
| 73 | + explicitComponents = append(explicitComponents, c) |
| 74 | + } |
| 75 | + } |
| 76 | + // The maximum total length of components is determined by subtracting length |
| 77 | + // of the following substring from the maximum length of resource name: |
| 78 | + // * prefix |
| 79 | + // * separators "-". There will be len(explicitComponents) + 1 of them. |
| 80 | + // * hash |
| 81 | + componentsMaxLen := resourceNameMaxLen - len(prefix) - (len(explicitComponents) + 1) - len(resourceHash) |
| 82 | + // Drop components from the resource name if the allowed maximum total length |
| 83 | + // of them is less them the total number of components. (This happens when |
| 84 | + // there are too many components) |
| 85 | + if componentsMaxLen < len(explicitComponents) { |
| 86 | + return fmt.Sprintf("%s-%s", prefix, resourceHash) |
| 87 | + } |
| 88 | + // Trim components to fit the allowed maximum total length. |
| 89 | + trimmed := TrimFieldsEvenly(componentsMaxLen, explicitComponents...) |
| 90 | + return fmt.Sprintf("%s-%s-%s", prefix, strings.Join(trimmed, "-"), resourceHash) |
| 91 | +} |
| 92 | + |
| 93 | +func allCharAllowedInResourceName(s string) bool { |
| 94 | + if len(s) == 0 { |
| 95 | + return false |
| 96 | + } |
| 97 | + for _, r := range s { |
| 98 | + if !(unicode.IsDigit(r) || unicode.IsLetter(r) || r == '-') { |
| 99 | + return false |
| 100 | + } |
| 101 | + } |
| 102 | + return true |
| 103 | +} |
0 commit comments