Skip to content

Commit 626b4f4

Browse files
committed
validate ProviderID equality by comparing entire string
1 parent 563f15a commit 626b4f4

File tree

5 files changed

+57
-24
lines changed

5 files changed

+57
-24
lines changed

controllers/noderefutil/providerid.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package noderefutil
1919

2020
import (
2121
"errors"
22-
"fmt"
2322
"regexp"
2423
"strings"
2524
)
@@ -87,9 +86,9 @@ func (p *ProviderID) ID() string {
8786
return p.id
8887
}
8988

90-
// Equals returns true if both the CloudProvider and ID match.
89+
// Equals returns true if this ProviderID string matches another ProviderID string.
9190
func (p *ProviderID) Equals(o *ProviderID) bool {
92-
return p.CloudProvider() == o.CloudProvider() && p.ID() == o.ID()
91+
return p.String() == o.String()
9392
}
9493

9594
// String returns the string representation of this object.
@@ -102,10 +101,8 @@ func (p *ProviderID) Validate() bool {
102101
return p.CloudProvider() != "" && p.ID() != ""
103102
}
104103

105-
// IndexKey returns a string concatenating the cloudProvider and the ID parts of the providerID.
106-
// E.g Format: cloudProvider://optional/segments/etc/id. IndexKey: cloudProvider/id
107-
// This is useful to use the providerID as a reliable index between nodes and machines
108-
// as it guarantees the infra Providers contract.
104+
// IndexKey returns the required level of uniqueness
105+
// to represent and index machines uniquely from their node providerID.
109106
func (p *ProviderID) IndexKey() string {
110-
return fmt.Sprintf("%s/%s", p.CloudProvider(), p.ID())
107+
return p.String()
111108
}

controllers/noderefutil/providerid_test.go

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
)
2424

2525
const aws = "aws"
26+
const azure = "azure"
2627

2728
func TestNewProviderID(t *testing.T) {
2829
tests := []struct {
@@ -115,19 +116,53 @@ func TestInvalidProviderID(t *testing.T) {
115116
func TestProviderIDEquals(t *testing.T) {
116117
g := NewWithT(t)
117118

118-
input1 := "aws:////instance-id1"
119-
parsed1, err := NewProviderID(input1)
119+
inputAWS1 := "aws:////instance-id1"
120+
parsedAWS1, err := NewProviderID(inputAWS1)
120121
g.Expect(err).NotTo(HaveOccurred())
121-
g.Expect(parsed1.String()).To(Equal(input1))
122-
g.Expect(parsed1.ID()).To(Equal("instance-id1"))
123-
g.Expect(parsed1.CloudProvider()).To(Equal(aws))
122+
g.Expect(parsedAWS1.String()).To(Equal(inputAWS1))
123+
g.Expect(parsedAWS1.ID()).To(Equal("instance-id1"))
124+
g.Expect(parsedAWS1.CloudProvider()).To(Equal(aws))
124125

125-
input2 := "aws:///us-west-1/instance-id1"
126-
parsed2, err := NewProviderID(input2)
126+
inputAWS2 := "aws:///us-west-1/instance-id1"
127+
parsedAWS2, err := NewProviderID(inputAWS2)
127128
g.Expect(err).NotTo(HaveOccurred())
128-
g.Expect(parsed2.String()).To(Equal(input2))
129-
g.Expect(parsed2.ID()).To(Equal("instance-id1"))
130-
g.Expect(parsed2.CloudProvider()).To(Equal(aws))
129+
g.Expect(parsedAWS2.String()).To(Equal(inputAWS2))
130+
g.Expect(parsedAWS2.ID()).To(Equal("instance-id1"))
131+
g.Expect(parsedAWS2.CloudProvider()).To(Equal(aws))
131132

132-
g.Expect(parsed1.Equals(parsed2)).To(BeTrue())
133+
// Test for inequality
134+
g.Expect(parsedAWS1.Equals(parsedAWS2)).To(BeFalse())
135+
136+
inputAzure1 := "azure:///subscriptions/4920076a-ba9f-11ec-8422-0242ac120002/resourceGroups/default-template/providers/Microsoft.Compute/virtualMachines/default-template-control-plane-fhrvh"
137+
parsedAzure1, err := NewProviderID(inputAzure1)
138+
g.Expect(err).NotTo(HaveOccurred())
139+
g.Expect(parsedAzure1.String()).To(Equal(inputAzure1))
140+
g.Expect(parsedAzure1.ID()).To(Equal("default-template-control-plane-fhrvh"))
141+
g.Expect(parsedAzure1.CloudProvider()).To(Equal(azure))
142+
143+
inputAzure2 := inputAzure1
144+
parsedAzure2, err := NewProviderID(inputAzure2)
145+
g.Expect(err).NotTo(HaveOccurred())
146+
147+
// Test for equality
148+
g.Expect(parsedAzure1.Equals(parsedAzure2)).To(BeTrue())
149+
150+
// Here we ensure that two different ProviderID strings that happen to have the same 'ID' are not equal
151+
// We use Azure VMSS as an example, two different '0' VMs in different pools: k8s-pool1-vmss, and k8s-pool2-vmss
152+
inputAzureVMFromOneVMSS := "azure:///subscriptions/4920076a-ba9f-11ec-8422-0242ac120002/resourceGroups/default-template/providers/Microsoft.Compute/virtualMachineScaleSets/k8s-pool1-vmss/virtualMachines/0"
153+
inputAzureVMFromAnotherVMSS := "azure:///subscriptions/4920076a-ba9f-11ec-8422-0242ac120002/resourceGroups/default-template/providers/Microsoft.Compute/virtualMachineScaleSets/k8s-pool2-vmss/virtualMachines/0"
154+
parsedAzureVMFromOneVMSS, err := NewProviderID(inputAzureVMFromOneVMSS)
155+
g.Expect(err).NotTo(HaveOccurred())
156+
g.Expect(parsedAzureVMFromOneVMSS.String()).To(Equal(inputAzureVMFromOneVMSS))
157+
g.Expect(parsedAzureVMFromOneVMSS.ID()).To(Equal("0"))
158+
g.Expect(parsedAzureVMFromOneVMSS.CloudProvider()).To(Equal(azure))
159+
160+
parsedAzureVMFromAnotherVMSS, err := NewProviderID(inputAzureVMFromAnotherVMSS)
161+
g.Expect(err).NotTo(HaveOccurred())
162+
g.Expect(parsedAzureVMFromAnotherVMSS.String()).To(Equal(inputAzureVMFromAnotherVMSS))
163+
g.Expect(parsedAzureVMFromAnotherVMSS.ID()).To(Equal("0"))
164+
g.Expect(parsedAzureVMFromAnotherVMSS.CloudProvider()).To(Equal(azure))
165+
166+
// Test for inequality
167+
g.Expect(parsedAzureVMFromOneVMSS.Equals(parsedAzureVMFromAnotherVMSS)).To(BeFalse())
133168
}

docs/book/src/developer/providers/v1.2-to-v1.3.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,4 @@ The default value is 0, meaning that the volume can be detached without any time
6262
* `COREDNS_VERSION_UPGRADE_TO`
6363
The variable `SkipUpgrade` could be set to revert to the old behaviour by making use of the `KUBERNETES_VERSION` variable and skipping the kubernetes upgrade.
6464
- cert-manager upgraded from v1.9.1 to v1.10.0.
65+
- Machine `providerID` is now being strictly checked for equality when compared against Kubernetes node `providerID` data. This is the expected criteria for correlating a Cluster API machine to its corresponding Kubernetes node, but historically this comparison was not strict, and instead compared only against the `ID` substring part of the full `providerID` string. Because different providers construct `providerID` strings differently, the `ID` substring is not uniformly defined and implemented across providers, and thus the existing `providerID` equality can not guarantee the correct Machine-Node correlation. It is very unlikely that this new behavior will break existing providers, but FYI: if strict `providerID` equality will degrade expected behaviors, you may need to update your provider implementation prior to adopting Cluster API v1.3.

internal/controllers/machine/machine_controller_noderef_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ func TestGetNode(t *testing.T) {
8181
ProviderID: "aws://us-west-2/test-get-node-2",
8282
},
8383
},
84-
providerIDInput: "aws:///test-get-node-2",
84+
providerIDInput: "aws://us-west-2/test-get-node-2",
8585
},
8686
{
8787
name: "gce prefix, cloudProvider and ID matches",
@@ -93,7 +93,7 @@ func TestGetNode(t *testing.T) {
9393
ProviderID: "gce://us-central1/test-get-node-2",
9494
},
9595
},
96-
providerIDInput: "gce:///test-get-node-2",
96+
providerIDInput: "gce://us-central1/test-get-node-2",
9797
},
9898
{
9999
name: "Node is not found",

internal/controllers/machine/machine_controller_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ func TestWatches(t *testing.T) {
100100
Namespace: ns.Name,
101101
},
102102
Spec: corev1.NodeSpec{
103-
ProviderID: "test:///id-1",
103+
ProviderID: "test://id-1",
104104
},
105105
}
106106

@@ -1800,7 +1800,7 @@ func TestNodeToMachine(t *testing.T) {
18001800
Name: "test-node-to-machine-1",
18011801
},
18021802
Spec: corev1.NodeSpec{
1803-
ProviderID: "test:///id-1",
1803+
ProviderID: "test://id-1",
18041804
},
18051805
}
18061806

@@ -1809,7 +1809,7 @@ func TestNodeToMachine(t *testing.T) {
18091809
Name: "test-node-to-machine-node-2",
18101810
},
18111811
Spec: corev1.NodeSpec{
1812-
ProviderID: "test:///id-2",
1812+
ProviderID: "test://id-2",
18131813
},
18141814
}
18151815

0 commit comments

Comments
 (0)