@@ -18,7 +18,7 @@ package vmservice
1818
1919import (
2020 "context"
21- "crypto/md5" // #nosec
21+ "crypto/sha256"
2222 "encoding/hex"
2323 "fmt"
2424 "reflect"
@@ -29,6 +29,7 @@ import (
2929 v1 "k8s.io/api/core/v1"
3030 apierrors "k8s.io/apimachinery/pkg/api/errors"
3131 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32+ "k8s.io/apimachinery/pkg/labels"
3233
3334 vmop "k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphereparavirtual/vmoperator"
3435 vmoptypes "k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphereparavirtual/vmoperator/types"
@@ -106,15 +107,50 @@ func NewVMService(vmClient vmop.Interface, ns string, ownerRef *metav1.OwnerRefe
106107}
107108
108109func (s * vmService ) hashString (str string ) string {
109- // #nosec
110- hash := md5 .New ()
110+ // SHA-256 is used as a FIPS-approved, well-distributed hash to derive a
111+ // deterministic name suffix. The output is later truncated to
112+ // MaxCheckSumLen; this is not a security-sensitive use.
113+ hash := sha256 .New ()
111114 if _ , err := hash .Write ([]byte (str )); err != nil {
112115 log .Error (err , "create hash string failed" )
113116 }
114117
115118 return hex .EncodeToString (hash .Sum (nil ))
116119}
117120
121+ // findLegacyVMService locates a VirtualMachineService that was created by an
122+ // older release using a different name-hashing scheme. It matches on the
123+ // identifying labels that the CPI has always stamped on every
124+ // VirtualMachineService, so the lookup is independent of how the name was
125+ // generated. Returns nil when no matching resource exists.
126+ //
127+ // Any List error (including a missing "list" RBAC permission) is logged and
128+ // treated as "no legacy resource found" so that the primary, name-based flow is
129+ // never blocked. In particular, a freshly created Service has no
130+ // VirtualMachineService yet and must still be able to proceed to Create.
131+ func (s * vmService ) findLegacyVMService (ctx context.Context , service * v1.Service , clusterName string ) * vmoptypes.VirtualMachineServiceInfo {
132+ logger := log .WithValues ("name" , service .Name , "namespace" , service .Namespace )
133+
134+ selector := labels .SelectorFromSet (labels.Set {
135+ LabelClusterNameKey : clusterName ,
136+ LabelServiceNameKey : service .Name ,
137+ LabelServiceNameSpaceKey : service .Namespace ,
138+ }).String ()
139+
140+ list , err := s .vmClient .VirtualMachineServices ().List (ctx , s .namespace , vmoptypes.ListOptions {LabelSelector : selector })
141+ if err != nil {
142+ logger .Error (err , "failed to list VirtualMachineServices for legacy lookup; treating as not found" )
143+ return nil
144+ }
145+ if len (list ) == 0 {
146+ return nil
147+ }
148+ if len (list ) > 1 {
149+ logger .V (2 ).Info ("multiple VirtualMachineServices matched the legacy label lookup; using the first" , "count" , len (list ))
150+ }
151+ return list [0 ]
152+ }
153+
118154// GetVMServiceName returns VirtualMachineService name for a lb type of service
119155func (s * vmService ) GetVMServiceName (service * v1.Service , clusterName string ) string {
120156 suffix := s .hashString (service .Name + "." + service .Namespace )
@@ -133,9 +169,17 @@ func (s *vmService) Get(ctx context.Context, service *v1.Service, clusterName st
133169 logger := log .WithValues ("name" , service .Name , "namespace" , service .Namespace )
134170 logger .V (2 ).Info ("Attempting to get VirtualMachineService" )
135171
136- vmService , err := s .vmClient .VirtualMachineServices ().Get (ctx , s .namespace , s .GetVMServiceName (service , clusterName ))
172+ name := s .GetVMServiceName (service , clusterName )
173+ vmService , err := s .vmClient .VirtualMachineServices ().Get (ctx , s .namespace , name )
137174 if err != nil {
138175 if apierrors .IsNotFound (err ) {
176+ // Fallback for resources created by an older release that used a
177+ // different name-hashing scheme. Located via the always-present
178+ // identifying labels rather than by recomputing the legacy name.
179+ if legacy := s .findLegacyVMService (ctx , service , clusterName ); legacy != nil {
180+ logger .V (2 ).Info ("VirtualMachineService not found by name; found legacy resource via labels" , "legacyName" , legacy .Name )
181+ return legacy , nil
182+ }
139183 return nil , nil
140184 }
141185 logger .Error (ErrGetVMService , fmt .Sprintf ("%v" , err ))
@@ -304,8 +348,27 @@ func (s *vmService) Delete(ctx context.Context, service *v1.Service, clusterName
304348 logger := log .WithValues ("name" , service .Name , "namespace" , service .Namespace )
305349 logger .V (2 ).Info ("Attempting to delete VirtualMachineService" )
306350
307- err := s .vmClient .VirtualMachineServices ().Delete (ctx , s .namespace , s .GetVMServiceName (service , clusterName ))
351+ name := s .GetVMServiceName (service , clusterName )
352+ err := s .vmClient .VirtualMachineServices ().Delete (ctx , s .namespace , name )
308353 if err != nil {
354+ if apierrors .IsNotFound (err ) {
355+ // Fallback: a resource created by an older release lives under a
356+ // different name. Locate it via the identifying labels and delete it.
357+ legacy := s .findLegacyVMService (ctx , service , clusterName )
358+ if legacy == nil {
359+ return nil
360+ }
361+ logger .V (2 ).Info ("VirtualMachineService not found by name; deleting legacy resource found via labels" , "legacyName" , legacy .Name )
362+ if derr := s .vmClient .VirtualMachineServices ().Delete (ctx , s .namespace , legacy .Name ); derr != nil {
363+ if apierrors .IsNotFound (derr ) {
364+ return nil
365+ }
366+ logger .Error (ErrDeleteVMService , fmt .Sprintf ("failed to delete legacy VirtualMachineService: %v" , derr ))
367+ return derr
368+ }
369+ logger .V (2 ).Info ("Successfully deleted legacy VirtualMachineService" )
370+ return nil
371+ }
309372 logger .Error (ErrDeleteVMService , fmt .Sprintf ("%v" , err ))
310373 return err
311374 }
0 commit comments