From a0742aef7c383991577adafb7ad7fea839ca6d3b Mon Sep 17 00:00:00 2001 From: Amit Watve Date: Mon, 1 Mar 2021 16:27:59 -0800 Subject: [PATCH] use a identifiable uuid prefix as default --- kubetest2-gce/deployer/deployer.go | 32 ++++++++++++--- kubetest2-gce/deployer/deployer_test.go | 54 +++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 kubetest2-gce/deployer/deployer_test.go diff --git a/kubetest2-gce/deployer/deployer.go b/kubetest2-gce/deployer/deployer.go index ccaf4059..e427afc3 100644 --- a/kubetest2-gce/deployer/deployer.go +++ b/kubetest2-gce/deployer/deployer.go @@ -81,6 +81,27 @@ type deployer struct { CreateCustomNetwork bool `desc:"Sets the environment variable CREATE_CUSTOM_NETWORK=true during deployment."` } +// pseudoUniqueSubstring returns a substring of a UUID +// that can be reasonably used in resource names +// where length is constrained +// e.g https://cloud.google.com/compute/docs/naming-resources +// but still retain as much uniqueness as possible +// also easily lets us tie it back to a run +func pseudoUniqueSubstring(uuid string) string { + // both KUBETEST2_RUN_ID and PROW_JOB_ID uuids are generated + // following RFC 4122 https://tools.ietf.org/html/rfc4122 + // e.g. 09a2565a-7ac6-11eb-a603-2218f636630c + // extract the first 13 characters (09a2565a-7ac6) as they are the ones that depend on + // timestamp and has the best avalanche effect (https://en.wikipedia.org/wiki/Avalanche_effect) + // as compared to the other bytes + // 13 characters is also <= the no. of character being used previously + const maxResourceNamePrefixLength = 13 + if len(uuid) <= maxResourceNamePrefixLength { + return uuid + } + return uuid[:maxResourceNamePrefixLength] +} + // New implements deployer.New for gce func New(opts types.Options) (types.Deployer, *pflag.FlagSet) { d := &deployer{ @@ -92,11 +113,12 @@ func New(opts types.Options) (types.Deployer, *pflag.FlagSet) { Strategy: "make", }, }, - kubeconfigPath: filepath.Join(opts.RunDir(), "kubetest2-kubeconfig"), - logsDir: filepath.Join(opts.RunDir(), "cluster-logs"), - boskosHeartbeatClose: make(chan struct{}), - instancePrefix: "kubetest2", - network: "default", + kubeconfigPath: filepath.Join(opts.RunDir(), "kubetest2-kubeconfig"), + logsDir: filepath.Join(opts.RunDir(), "cluster-logs"), + boskosHeartbeatClose: make(chan struct{}), + // names need to start with an alphabet + instancePrefix: "kt2-" + pseudoUniqueSubstring(opts.RunID()), + network: "kt2-" + pseudoUniqueSubstring(opts.RunID()), BoskosAcquireTimeoutSeconds: 5 * 60, BoskosLocation: "http://boskos.test-pods.svc.cluster.local.", NumNodes: 3, diff --git a/kubetest2-gce/deployer/deployer_test.go b/kubetest2-gce/deployer/deployer_test.go new file mode 100644 index 00000000..f83cb28a --- /dev/null +++ b/kubetest2-gce/deployer/deployer_test.go @@ -0,0 +1,54 @@ +/* +Copyright 2020 The Kubernetes Authors. + +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 deployer + +import "testing" + +func TestPseudoUniqueSubstring(t *testing.T) { + testCases := []struct { + name string + uuid string + expectedSubstring string + }{ + { + name: "actual uuid", + uuid: "09a2565a-7ac6-11eb-a603-2218f636630c", + expectedSubstring: "09a2565a-7ac6", + }, + { + name: "<= 13 length uuid", + uuid: "09a2565a-7ac6", + expectedSubstring: "09a2565a-7ac6", + }, + { + name: "empty string", + uuid: "", + expectedSubstring: "", + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + actualSubstring := pseudoUniqueSubstring(tc.uuid) + if actualSubstring != tc.expectedSubstring { + t.Errorf("invalid substring: expected %s, but got %s", tc.expectedSubstring, actualSubstring) + } + }) + } +}