From 5be7a26211ccd4186d50878941c2aa9645c0e548 Mon Sep 17 00:00:00 2001 From: Ciprian Hacman Date: Mon, 17 Jul 2023 05:36:12 +0300 Subject: [PATCH] azure: Use k8s.io/utils/set.Set[string] --- pkg/resources/azure/azure.go | 21 +-- vendor/k8s.io/utils/set/OWNERS | 8 + vendor/k8s.io/utils/set/ordered.go | 53 +++++++ vendor/k8s.io/utils/set/set.go | 229 +++++++++++++++++++++++++++++ vendor/modules.txt | 1 + 5 files changed, 302 insertions(+), 10 deletions(-) create mode 100644 vendor/k8s.io/utils/set/OWNERS create mode 100644 vendor/k8s.io/utils/set/ordered.go create mode 100644 vendor/k8s.io/utils/set/set.go diff --git a/pkg/resources/azure/azure.go b/pkg/resources/azure/azure.go index 24c6f08be26f7..5fd676b7bf987 100644 --- a/pkg/resources/azure/azure.go +++ b/pkg/resources/azure/azure.go @@ -27,6 +27,7 @@ import ( "k8s.io/kops/pkg/resources" "k8s.io/kops/upup/pkg/fi" "k8s.io/kops/upup/pkg/fi/cloudup/azure" + "k8s.io/utils/set" ) const ( @@ -168,7 +169,7 @@ func (g *resourceGetter) toVirtualNetworkResource(vnet *network.VirtualNetwork) var blocks []string blocks = append(blocks, toKey(typeResourceGroup, g.resourceGroupName())) - nsgs := map[string]struct{}{} + nsgs := set.New[string]() if vnet.Subnets != nil { for _, sn := range *vnet.Subnets { if sn.NetworkSecurityGroup != nil { @@ -176,7 +177,7 @@ func (g *resourceGetter) toVirtualNetworkResource(vnet *network.VirtualNetwork) if err != nil { return nil, fmt.Errorf("parsing network security group ID: %s", err) } - nsgs[nsgID.NetworkSecurityGroupName] = struct{}{} + nsgs.Insert(nsgID.NetworkSecurityGroupName) } } } @@ -341,24 +342,24 @@ func (g *resourceGetter) toVMScaleSetResource(vmss *compute.VirtualMachineScaleS var blocks []string blocks = append(blocks, toKey(typeResourceGroup, g.resourceGroupName())) - vnets := map[string]struct{}{} - subnets := map[string]struct{}{} - lbs := map[string]struct{}{} + vnets := set.New[string]() + subnets := set.New[string]() + lbs := set.New[string]() for _, iface := range *vmss.VirtualMachineProfile.NetworkProfile.NetworkInterfaceConfigurations { for _, ip := range *iface.IPConfigurations { subnetID, err := azure.ParseSubnetID(*ip.Subnet.ID) if err != nil { return nil, fmt.Errorf("error on parsing subnet ID: %s", err) } - vnets[subnetID.VirtualNetworkName] = struct{}{} - subnets[subnetID.SubnetName] = struct{}{} + vnets.Insert(subnetID.VirtualNetworkName) + subnets.Insert(subnetID.SubnetName) if ip.LoadBalancerBackendAddressPools != nil { for _, lb := range *ip.LoadBalancerBackendAddressPools { lbID, err := azure.ParseLoadBalancerID(*lb.ID) if err != nil { return nil, fmt.Errorf("parsing load balancer ID: %s", err) } - lbs[lbID.LoadBalancerName] = struct{}{} + lbs.Insert(lbID.LoadBalancerName) } } } @@ -496,7 +497,7 @@ func (g *resourceGetter) toLoadBalancerResource(loadBalancer *network.LoadBalanc var blocks []string blocks = append(blocks, toKey(typeResourceGroup, g.resourceGroupName())) - pips := map[string]struct{}{} + pips := set.New[string]() if loadBalancer.FrontendIPConfigurations != nil { for _, fip := range *loadBalancer.FrontendIPConfigurations { if fip.PublicIPAddress != nil { @@ -504,7 +505,7 @@ func (g *resourceGetter) toLoadBalancerResource(loadBalancer *network.LoadBalanc if err != nil { return nil, fmt.Errorf("parsing public IP address ID: %s", err) } - pips[pipID.PublicIPAddressName] = struct{}{} + pips.Insert(pipID.PublicIPAddressName) } } } diff --git a/vendor/k8s.io/utils/set/OWNERS b/vendor/k8s.io/utils/set/OWNERS new file mode 100644 index 0000000000000..9d2d33e7b0ddd --- /dev/null +++ b/vendor/k8s.io/utils/set/OWNERS @@ -0,0 +1,8 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +reviewers: + - logicalhan + - thockin +approvers: + - logicalhan + - thockin diff --git a/vendor/k8s.io/utils/set/ordered.go b/vendor/k8s.io/utils/set/ordered.go new file mode 100644 index 0000000000000..2b2c11fc7b46d --- /dev/null +++ b/vendor/k8s.io/utils/set/ordered.go @@ -0,0 +1,53 @@ +/* +Copyright 2023 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 set + +// ordered is a constraint that permits any ordered type: any type +// that supports the operators < <= >= >. +// If future releases of Go add new ordered types, +// this constraint will be modified to include them. +type ordered interface { + integer | float | ~string +} + +// integer is a constraint that permits any integer type. +// If future releases of Go add new predeclared integer types, +// this constraint will be modified to include them. +type integer interface { + signed | unsigned +} + +// float is a constraint that permits any floating-point type. +// If future releases of Go add new predeclared floating-point types, +// this constraint will be modified to include them. +type float interface { + ~float32 | ~float64 +} + +// signed is a constraint that permits any signed integer type. +// If future releases of Go add new predeclared signed integer types, +// this constraint will be modified to include them. +type signed interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 +} + +// unsigned is a constraint that permits any unsigned integer type. +// If future releases of Go add new predeclared unsigned integer types, +// this constraint will be modified to include them. +type unsigned interface { + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr +} diff --git a/vendor/k8s.io/utils/set/set.go b/vendor/k8s.io/utils/set/set.go new file mode 100644 index 0000000000000..172482cdc1e17 --- /dev/null +++ b/vendor/k8s.io/utils/set/set.go @@ -0,0 +1,229 @@ +/* +Copyright 2023 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 set + +import ( + "sort" +) + +// Empty is public since it is used by some internal API objects for conversions between external +// string arrays and internal sets, and conversion logic requires public types today. +type Empty struct{} + +// Set is a set of the same type elements, implemented via map[ordered]struct{} for minimal memory consumption. +type Set[E ordered] map[E]Empty + +// New creates a new set. +func New[E ordered](items ...E) Set[E] { + ss := Set[E]{} + ss.Insert(items...) + return ss +} + +// KeySet creates a Set[E] from a keys of a map[E](? extends interface{}). +func KeySet[E ordered, A any](theMap map[E]A) Set[E] { + ret := Set[E]{} + for key := range theMap { + ret.Insert(key) + } + return ret +} + +// Insert adds items to the set. +func (s Set[E]) Insert(items ...E) Set[E] { + for _, item := range items { + s[item] = Empty{} + } + return s +} + +// Delete removes all items from the set. +func (s Set[E]) Delete(items ...E) Set[E] { + for _, item := range items { + delete(s, item) + } + return s +} + +// Has returns true if and only if item is contained in the set. +func (s Set[E]) Has(item E) bool { + _, contained := s[item] + return contained +} + +// HasAll returns true if and only if all items are contained in the set. +func (s Set[E]) HasAll(items ...E) bool { + for _, item := range items { + if !s.Has(item) { + return false + } + } + return true +} + +// HasAny returns true if any items are contained in the set. +func (s Set[E]) HasAny(items ...E) bool { + for _, item := range items { + if s.Has(item) { + return true + } + } + return false +} + +// Union returns a new set which includes items in either s1 or s2. +// For example: +// s1 = {a1, a2} +// s2 = {a3, a4} +// s1.Union(s2) = {a1, a2, a3, a4} +// s2.Union(s1) = {a1, a2, a3, a4} +func (s Set[E]) Union(s2 Set[E]) Set[E] { + result := Set[E]{} + result.Insert(s.UnsortedList()...) + result.Insert(s2.UnsortedList()...) + return result +} + +// Len returns the number of elements in the set. +func (s Set[E]) Len() int { + return len(s) +} + +// Intersection returns a new set which includes the item in BOTH s1 and s2 +// For example: +// s1 = {a1, a2} +// s2 = {a2, a3} +// s1.Intersection(s2) = {a2} +func (s Set[E]) Intersection(s2 Set[E]) Set[E] { + var walk, other Set[E] + result := Set[E]{} + if s.Len() < s2.Len() { + walk = s + other = s2 + } else { + walk = s2 + other = s + } + for key := range walk { + if other.Has(key) { + result.Insert(key) + } + } + return result +} + +// IsSuperset returns true if and only if s1 is a superset of s2. +func (s Set[E]) IsSuperset(s2 Set[E]) bool { + for item := range s2 { + if !s.Has(item) { + return false + } + } + return true +} + +// Difference returns a set of objects that are not in s2 +// For example: +// s1 = {a1, a2, a3} +// s2 = {a1, a2, a4, a5} +// s1.Difference(s2) = {a3} +// s2.Difference(s1) = {a4, a5} +func (s Set[E]) Difference(s2 Set[E]) Set[E] { + result := Set[E]{} + for key := range s { + if !s2.Has(key) { + result.Insert(key) + } + } + return result +} + +// Equal returns true if and only if s1 is equal (as a set) to s2. +// Two sets are equal if their membership is identical. +func (s Set[E]) Equal(s2 Set[E]) bool { + return s.Len() == s.Len() && s.IsSuperset(s2) +} + +type sortableSlice[E ordered] []E + +func (s sortableSlice[E]) Len() int { + return len(s) +} +func (s sortableSlice[E]) Less(i, j int) bool { return s[i] < s[j] } +func (s sortableSlice[E]) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +// SortedList returns the contents as a sorted slice. +func (s Set[E]) SortedList() []E { + res := make(sortableSlice[E], 0, s.Len()) + for key := range s { + res = append(res, key) + } + sort.Sort(res) + return res +} + +// UnsortedList returns the slice with contents in random order. +func (s Set[E]) UnsortedList() []E { + res := make([]E, 0, len(s)) + for key := range s { + res = append(res, key) + } + return res +} + +// PopAny returns a single element from the set. +func (s Set[E]) PopAny() (E, bool) { + for key := range s { + s.Delete(key) + return key, true + } + var zeroValue E + return zeroValue, false +} + +// Clone returns a new set which is a copy of the current set. +func (s Set[T]) Clone() Set[T] { + result := make(Set[T], len(s)) + for key := range s { + result.Insert(key) + } + return result +} + +// SymmetricDifference returns a set of elements which are in either of the sets, but not in their intersection. +// For example: +// s1 = {a1, a2, a3} +// s2 = {a1, a2, a4, a5} +// s1.SymmetricDifference(s2) = {a3, a4, a5} +// s2.SymmetricDifference(s1) = {a3, a4, a5} +func (s Set[T]) SymmetricDifference(s2 Set[T]) Set[T] { + return s.Difference(s2).Union(s2.Difference(s)) +} + +// Clear empties the set. +// It is preferable to replace the set with a newly constructed set, +// but not all callers can do that (when there are other references to the map). +// In some cases the set *won't* be fully cleared, e.g. a Set[float32] containing NaN +// can't be cleared because NaN can't be removed. +// For sets containing items of a type that is reflexive for ==, +// this is optimized to a single call to runtime.mapclear(). +func (s Set[T]) Clear() Set[T] { + for key := range s { + delete(s, key) + } + return s +} diff --git a/vendor/modules.txt b/vendor/modules.txt index d3733663e4e71..7ed0d4e082909 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1747,6 +1747,7 @@ k8s.io/utils/io k8s.io/utils/keymutex k8s.io/utils/net k8s.io/utils/pointer +k8s.io/utils/set k8s.io/utils/strings/slices k8s.io/utils/trace # oras.land/oras-go v1.2.3