diff --git a/go.mod b/go.mod index 9552315417..b7eecd30d4 100644 --- a/go.mod +++ b/go.mod @@ -16,9 +16,9 @@ require ( ) require ( - github.com/Masterminds/sprig/v3 v3.3.0 github.com/blang/semver/v4 v4.0.0 github.com/go-logr/logr v1.4.2 + github.com/go-task/slim-sprig/v3 v3.0.0 github.com/google/gofuzz v1.2.0 github.com/google/uuid v1.6.0 github.com/onsi/ginkgo/v2 v2.22.2 @@ -56,18 +56,12 @@ require ( github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.3.0 // indirect - github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/google/btree v1.1.3 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect - github.com/huandu/xstrings v1.5.0 // indirect - github.com/mitchellh/copystructure v1.2.0 // indirect - github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/shopspring/decimal v1.4.0 // indirect - github.com/spf13/cast v1.7.0 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/x448/float16 v0.8.4 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect @@ -80,7 +74,6 @@ require ( go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.32.0 // indirect golang.org/x/net v0.34.0 // indirect golang.org/x/oauth2 v0.25.0 // indirect golang.org/x/sync v0.10.0 // indirect diff --git a/go.sum b/go.sum index 155c190af9..8b8066ef49 100644 --- a/go.sum +++ b/go.sum @@ -61,8 +61,6 @@ github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0 github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= -github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= diff --git a/internal/webhooks/vspheremachinetemplate_test.go b/internal/webhooks/vspheremachinetemplate_test.go index 00dedad3f4..39fd447b97 100644 --- a/internal/webhooks/vspheremachinetemplate_test.go +++ b/internal/webhooks/vspheremachinetemplate_test.go @@ -99,11 +99,7 @@ func TestVSphereMachineTemplate_ValidateCreate(t *testing.T) { vsphereMachine: createVSphereMachineTemplate("foo.com", "vmx-17", nil, "", []string{}, []infrav1.PCIDeviceSpec{{VGPUProfile: "vgpu"}}, nil), }, { - name: "successful VSphereMachine creation with hardware version set", - vsphereMachine: createVSphereMachineTemplate("foo.com", "vmx-17", nil, "", []string{}, nil, nil), - }, - { - name: "successful VSphereMachineTemplate creation with namingStrategy not set", + name: "successful VSphereMachine creation with hardware version set and namingStrategy not set", vsphereMachine: createVSphereMachineTemplate("foo.com", "vmx-17", nil, "", []string{}, nil, nil), }, { diff --git a/packaging/go.sum b/packaging/go.sum index 364f9f1a3b..1c36be9bf1 100644 --- a/packaging/go.sum +++ b/packaging/go.sum @@ -1,13 +1,5 @@ -dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= -dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= -github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= -github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= -github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= -github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= -github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= @@ -70,10 +62,6 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaU github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= -github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= -github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -91,10 +79,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= -github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= -github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -126,10 +110,6 @@ github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= -github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= -github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= -github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -175,10 +155,6 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= -golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= diff --git a/pkg/services/vimmachine.go b/pkg/services/vimmachine.go index 7b19e2808b..481b815d64 100644 --- a/pkg/services/vimmachine.go +++ b/pkg/services/vimmachine.go @@ -18,13 +18,10 @@ limitations under the License. package services import ( - "bytes" "context" "encoding/json" "strings" - "text/template" - "github.com/Masterminds/sprig/v3" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -423,17 +420,6 @@ func generateVMObjectName(vimMachineCtx *capvcontext.VIMMachineContext, machineN return name, nil } -const ( - maxNameLength = 63 -) - -var nameTemplateFuncs = map[string]any{ - "trimSuffix": sprig.GenericFuncMap()["trimSuffix"], - "trunc": sprig.GenericFuncMap()["trunc"], -} - -var nameTpl = template.New("name generator").Funcs(nameTemplateFuncs).Option("missingkey=error") - // GenerateVSphereVMName generates the name of a VSphereVM based on the naming strategy. func GenerateVSphereVMName(machineName string, namingStrategy *infrav1.VSphereVMNamingStrategy) (string, error) { // Per default the name of the VSphereVM should be equal to the Machine name (this is the same as "{{ .machine.name }}") @@ -442,29 +428,9 @@ func GenerateVSphereVMName(machineName string, namingStrategy *infrav1.VSphereVM return machineName, nil } - nameTemplate := *namingStrategy.Template - data := map[string]interface{}{ - "machine": map[string]interface{}{ - "name": machineName, - }, - } - - tpl, err := nameTpl.Parse(nameTemplate) + name, err := infrautilv1.GenerateNameFromMachineNameTemplate(machineName, namingStrategy.Template) if err != nil { - return "", errors.Wrapf(err, "failed to generate name for VSphereVM: failed to parse namingStrategy.template %q", nameTemplate) - } - - var buf bytes.Buffer - if err := tpl.Execute(&buf, data); err != nil { - return "", errors.Wrap(err, "failed to generate name for VSphereVM") - } - - name := buf.String() - - // If the name exceeds the maxNameLength, trim to maxNameLength. - // Note: we're not adding a random suffix as the name has to be deterministic. - if len(name) > maxNameLength { - name = name[:maxNameLength] + return name, errors.Wrap(err, "failed to generate name for VSphereVM") } return name, nil diff --git a/pkg/services/vimmachine_test.go b/pkg/services/vimmachine_test.go index ef53aac3eb..dcc1c7c9c4 100644 --- a/pkg/services/vimmachine_test.go +++ b/pkg/services/vimmachine_test.go @@ -907,6 +907,8 @@ func Test_VimMachineService_SyncFailureReason(t *testing.T) { } func Test_GenerateVSphereVMName(t *testing.T) { + maxNameLength := 63 + tests := []struct { name string machineName string diff --git a/pkg/services/vmoperator/vmopmachine.go b/pkg/services/vmoperator/vmopmachine.go index a02f5f2809..2c1f2540c1 100644 --- a/pkg/services/vmoperator/vmopmachine.go +++ b/pkg/services/vmoperator/vmopmachine.go @@ -17,13 +17,10 @@ limitations under the License. package vmoperator import ( - "bytes" "context" "encoding/json" "fmt" - "text/template" - "github.com/Masterminds/sprig/v3" "github.com/pkg/errors" vmoprv1 "github.com/vmware-tanzu/vm-operator/api/v1alpha2" vmoprv1common "github.com/vmware-tanzu/vm-operator/api/v1alpha2/common" @@ -290,17 +287,6 @@ func (v *VmopMachineService) ReconcileNormal(ctx context.Context, machineCtx cap return false, nil } -const ( - maxNameLength = 63 -) - -var nameTemplateFuncs = map[string]any{ - "trimSuffix": sprig.GenericFuncMap()["trimSuffix"], - "trunc": sprig.GenericFuncMap()["trunc"], -} - -var nameTpl = template.New("name generator").Funcs(nameTemplateFuncs).Option("missingkey=error") - // virtualMachineObjectKey returns the object key of the VirtualMachine. // Part of this is generating the name of the VirtualMachine based on the naming strategy. func virtualMachineObjectKey(machineName, machineNamespace string, namingStrategy *vmwarev1.VirtualMachineNamingStrategy) (*client.ObjectKey, error) { @@ -323,31 +309,11 @@ func GenerateVirtualMachineName(machineName string, namingStrategy *vmwarev1.Vir return machineName, nil } - nameTemplate := *namingStrategy.Template - data := map[string]interface{}{ - "machine": map[string]interface{}{ - "name": machineName, - }, - } - - tpl, err := nameTpl.Parse(nameTemplate) + name, err := infrautilv1.GenerateNameFromMachineNameTemplate(machineName, namingStrategy.Template) if err != nil { - return "", errors.Wrapf(err, "failed to generate name for VirtualMachine: failed to parse namingStrategy.template %q", nameTemplate) - } - - var buf bytes.Buffer - if err := tpl.Execute(&buf, data); err != nil { return "", errors.Wrap(err, "failed to generate name for VirtualMachine") } - name := buf.String() - - // If the name exceeds the maxNameLength, trim to maxNameLength. - // Note: we're not adding a random suffix as the name has to be deterministic. - if len(name) > maxNameLength { - name = name[:maxNameLength] - } - return name, nil } diff --git a/pkg/services/vmoperator/vmopmachine_test.go b/pkg/services/vmoperator/vmopmachine_test.go index 1d4aec4adf..69a3d9076c 100644 --- a/pkg/services/vmoperator/vmopmachine_test.go +++ b/pkg/services/vmoperator/vmopmachine_test.go @@ -655,6 +655,10 @@ var _ = Describe("GetMachinesInCluster", func() { }) }) +const ( + maxNameLength = 63 +) + func Test_virtualMachineObjectKey(t *testing.T) { tests := []struct { name string diff --git a/pkg/util/template.go b/pkg/util/template.go new file mode 100644 index 0000000000..17f8358103 --- /dev/null +++ b/pkg/util/template.go @@ -0,0 +1,75 @@ +/* +Copyright 2025 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 util + +import ( + "bytes" + "fmt" + "text/template" + + sprig "github.com/go-task/slim-sprig/v3" + "github.com/pkg/errors" +) + +const ( + maxNameLength = 63 +) + +var nameTemplateFuncs = map[string]any{ + "trimSuffix": sprig.GenericFuncMap()["trimSuffix"], + "trunc": sprig.GenericFuncMap()["trunc"], +} + +var nameTpl = template.New("name generator").Funcs(nameTemplateFuncs).Option("missingkey=error") + +// GenerateNameFromMachineNameTemplate generate a name from machine name and a naming strategy template. +// the template supports only `trimSuffix` and `trunc` functions. +func GenerateNameFromMachineNameTemplate(machineName string, nameTemplate *string) (string, error) { + if machineName == "" { + return "", fmt.Errorf("machine name can not be emmpty") + } + + if nameTemplate == nil { + return machineName, nil + } + + data := map[string]interface{}{ + "machine": map[string]interface{}{ + "name": machineName, + }, + } + + tpl, err := nameTpl.Parse(*nameTemplate) + if err != nil { + return "", errors.Wrapf(err, "failed to generate name: failed to parse template %q", *nameTemplate) + } + + var buf bytes.Buffer + if err := tpl.Execute(&buf, data); err != nil { + return "", errors.Wrap(err, "failed to generate name") + } + + name := buf.String() + + // If the name exceeds the maxNameLength, trim to maxNameLength. + // Note: we're not adding a random suffix as the name has to be deterministic. + if len(name) > maxNameLength { + name = name[:maxNameLength] + } + + return name, nil +} diff --git a/pkg/util/template_test.go b/pkg/util/template_test.go new file mode 100644 index 0000000000..fc8ad1183e --- /dev/null +++ b/pkg/util/template_test.go @@ -0,0 +1,105 @@ +/* +Copyright 2025 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 util + +import ( + "testing" + + . "github.com/onsi/gomega" + gomegatypes "github.com/onsi/gomega/types" + "k8s.io/utils/ptr" +) + +func Test_GenerateVSphereVMName(t *testing.T) { + tests := []struct { + name string + machineName string + template *string + want []gomegatypes.GomegaMatcher + wantErr bool + }{ + { + name: "default template", + machineName: "quick-start-d34gt4-md-0-wqc85-8nxwc-gfd5v", + template: nil, + want: []gomegatypes.GomegaMatcher{ + Equal("quick-start-d34gt4-md-0-wqc85-8nxwc-gfd5v"), + }, + }, + { + name: "template which doesn't respect max length: trim to max length", + machineName: "quick-start-d34gt4-md-0-wqc85-8nxwc-gfd5v", // 41 characters + template: ptr.To[string]("{{ .machine.name }}-{{ .machine.name }}"), + want: []gomegatypes.GomegaMatcher{ + Equal("quick-start-d34gt4-md-0-wqc85-8nxwc-gfd5v-quick-start-d34gt4-md"), // 63 characters + }, + }, + { + name: "template for 20 characters: keep machine name if name has 20 characters", + machineName: "quick-md-8nxwc-gfd5v", // 20 characters + template: ptr.To[string]("{{ if le (len .machine.name) 20 }}{{ .machine.name }}{{else}}{{ trimSuffix \"-\" (trunc 14 .machine.name) }}-{{ trunc -5 .machine.name }}{{end}}"), + want: []gomegatypes.GomegaMatcher{ + Equal("quick-md-8nxwc-gfd5v"), // 20 characters + }, + }, + { + name: "template for 20 characters: trim to 20 characters if name has more than 20 characters", + machineName: "quick-start-d34gt4-md-0-wqc85-8nxwc-gfd5v", // 41 characters + template: ptr.To[string]("{{ if le (len .machine.name) 20 }}{{ .machine.name }}{{else}}{{ trimSuffix \"-\" (trunc 14 .machine.name) }}-{{ trunc -5 .machine.name }}{{end}}"), + want: []gomegatypes.GomegaMatcher{ + Equal("quick-start-d3-gfd5v"), // 20 characters + }, + }, + { + name: "template for 20 characters: trim to 19 characters if name has more than 20 characters and last character of prefix is -", + machineName: "quick-start-d-34gt4-md-0-wqc85-8nxwc-gfd5v", // 42 characters + template: ptr.To[string]("{{ if le (len .machine.name) 20 }}{{ .machine.name }}{{else}}{{ trimSuffix \"-\" (trunc 14 .machine.name) }}-{{ trunc -5 .machine.name }}{{end}}"), + want: []gomegatypes.GomegaMatcher{ + Equal("quick-start-d-gfd5v"), // 19 characters + }, + }, + { + name: "template with a prefix and only 5 random character from the machine name", + machineName: "quick-start-d-34gt4-md-0-wqc85-8nxwc-gfd5v", // 42 characters + template: ptr.To[string]("vm-{{ trunc -5 .machine.name }}"), + want: []gomegatypes.GomegaMatcher{ + Equal("vm-gfd5v"), // 8 characters + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + got, err := GenerateNameFromMachineNameTemplate(tt.machineName, tt.template) + + if (err != nil) != tt.wantErr { + t.Errorf("GenerateVSphereVMName error = %v, wantErr %v", err, tt.wantErr) + return + } + + if len(got) > maxNameLength { + t.Errorf("generated name should never be longer than %d, got %d", maxNameLength, len(got)) + } + + for _, matcher := range tt.want { + g.Expect(got).To(matcher) + } + }) + } +}