Skip to content

Commit

Permalink
Normalize providerID values
Browse files Browse the repository at this point in the history
We index on providerID but it turns out that those values on node and
machine are not always consistent. Some encode region, some do not,
for example.

This commit normalizes all values through the normalizedProviderString().

To ensure that we catch all places I've introduced a new type and made
the find() functions take this new type in lieu of a string. Unit
tests have also been adjusted to introduce a 'test:///' prefix on the
providerID value to further validate the change.

This change allows CAPI to work out-of-the-box, assuming v1alpha2.

It's also reasonable to assert that this consistency should be
enforced elsewhere and to make this behaviour easily revertable I'm
leaving this as a separate commit in this patch series.
  • Loading branch information
frobware committed Mar 9, 2020
1 parent 8fdac4c commit cf4575f
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,13 @@ func indexMachineByProviderID(obj interface{}) ([]string, error) {
return nil, nil
}

return []string{providerID}, nil
return []string{string(normalizedProviderString(providerID))}, nil
}

func indexNodeByProviderID(obj interface{}) ([]string, error) {
if node, ok := obj.(*corev1.Node); ok {
if node.Spec.ProviderID != "" {
return []string{node.Spec.ProviderID}, nil
return []string{string(normalizedProviderString(node.Spec.ProviderID))}, nil
}
return []string{}, nil
}
Expand Down Expand Up @@ -191,8 +191,8 @@ func (c *machineController) run(stopCh <-chan struct{}) error {

// findMachineByProviderID finds machine matching providerID. A
// DeepCopy() of the object is returned on success.
func (c *machineController) findMachineByProviderID(providerID string) (*Machine, error) {
objs, err := c.machineInformer.Informer().GetIndexer().ByIndex(machineProviderIDIndex, providerID)
func (c *machineController) findMachineByProviderID(providerID normalizedProviderID) (*Machine, error) {
objs, err := c.machineInformer.Informer().GetIndexer().ByIndex(machineProviderIDIndex, string(providerID))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -447,7 +447,7 @@ func (c *machineController) nodeGroups() ([]*nodegroup, error) {
}

func (c *machineController) nodeGroupForNode(node *corev1.Node) (*nodegroup, error) {
machine, err := c.findMachineByProviderID(node.Spec.ProviderID)
machine, err := c.findMachineByProviderID(normalizedProviderString(node.Spec.ProviderID))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -504,8 +504,8 @@ func (c *machineController) nodeGroupForNode(node *corev1.Node) (*nodegroup, err
// findNodeByProviderID find the Node object keyed by provideID.
// Returns nil if it cannot be found. A DeepCopy() of the object is
// returned on success.
func (c *machineController) findNodeByProviderID(providerID string) (*corev1.Node, error) {
objs, err := c.nodeInformer.GetIndexer().ByIndex(nodeProviderIDIndex, providerID)
func (c *machineController) findNodeByProviderID(providerID normalizedProviderID) (*corev1.Node, error) {
objs, err := c.nodeInformer.GetIndexer().ByIndex(nodeProviderIDIndex, string(providerID))
if err != nil {
return nil, err
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ func makeLinkedNodeAndMachine(i int, namespace string, owner v1.OwnerReference)
},
},
Spec: corev1.NodeSpec{
ProviderID: fmt.Sprintf("%s-%s-nodeid-%d", namespace, owner.Name, i),
ProviderID: fmt.Sprintf("test:////%s-%s-nodeid-%d", namespace, owner.Name, i),
},
}

Expand All @@ -224,7 +224,7 @@ func makeLinkedNodeAndMachine(i int, namespace string, owner v1.OwnerReference)
}},
},
Spec: MachineSpec{
ProviderID: pointer.StringPtr(fmt.Sprintf("%s-%s-nodeid-%d", namespace, owner.Name, i)),
ProviderID: pointer.StringPtr(fmt.Sprintf("test:////%s-%s-nodeid-%d", namespace, owner.Name, i)),
},
Status: MachineStatus{
NodeRef: &corev1.ObjectReference{
Expand Down Expand Up @@ -421,7 +421,7 @@ func TestControllerFindMachineByProviderID(t *testing.T) {
}

// Test #1: Verify underlying machine provider ID matches
machine, err := controller.findMachineByProviderID(testConfig.nodes[0].Spec.ProviderID)
machine, err := controller.findMachineByProviderID(normalizedProviderString(testConfig.nodes[0].Spec.ProviderID))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
Expand All @@ -440,7 +440,7 @@ func TestControllerFindMachineByProviderID(t *testing.T) {
if err := controller.machineInformer.Informer().GetStore().Update(machine); err != nil {
t.Fatalf("unexpected error updating machine, got %v", err)
}
machine, err = controller.findMachineByProviderID(testConfig.nodes[0].Spec.ProviderID)
machine, err = controller.findMachineByProviderID(normalizedProviderString(testConfig.nodes[0].Spec.ProviderID))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
Expand Down Expand Up @@ -824,7 +824,7 @@ func TestControllerFindMachineFromNodeAnnotation(t *testing.T) {
}

// Test #1: Verify machine can be found from node annotation
machine, err := controller.findMachineByProviderID(testConfig.nodes[0].Spec.ProviderID)
machine, err := controller.findMachineByProviderID(normalizedProviderString(testConfig.nodes[0].Spec.ProviderID))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
Expand All @@ -842,7 +842,7 @@ func TestControllerFindMachineFromNodeAnnotation(t *testing.T) {
if err := controller.nodeInformer.GetStore().Update(node); err != nil {
t.Fatalf("unexpected error updating node, got %v", err)
}
machine, err = controller.findMachineByProviderID(testConfig.nodes[0].Spec.ProviderID)
machine, err = controller.findMachineByProviderID(normalizedProviderString(testConfig.nodes[0].Spec.ProviderID))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
Expand Down Expand Up @@ -938,7 +938,7 @@ func TestControllerMachineSetNodeNamesUsingProviderID(t *testing.T) {
})

for i := range testConfig.nodes {
if nodeNames[i].Id != testConfig.nodes[i].Spec.ProviderID {
if nodeNames[i].Id != string(normalizedProviderString(testConfig.nodes[i].Spec.ProviderID)) {
t.Fatalf("expected %q, got %q", testConfig.nodes[i].Spec.ProviderID, nodeNames[i].Id)
}
}
Expand Down Expand Up @@ -986,7 +986,7 @@ func TestControllerMachineSetNodeNamesUsingStatusNodeRefName(t *testing.T) {
})

for i := range testConfig.nodes {
if nodeNames[i].Id != testConfig.nodes[i].Spec.ProviderID {
if nodeNames[i].Id != string(normalizedProviderString(testConfig.nodes[i].Spec.ProviderID)) {
t.Fatalf("expected %q, got %q", testConfig.nodes[i].Spec.ProviderID, nodeNames[i].Id)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func (ng *nodegroup) DeleteNodes(nodes []*corev1.Node) error {
// suitable candidate for deletion and drop the replica count
// by 1. Fail fast on any error.
for _, node := range nodes {
machine, err := ng.machineController.findMachineByProviderID(node.Spec.ProviderID)
machine, err := ng.machineController.findMachineByProviderID(normalizedProviderString(node.Spec.ProviderID))
if err != nil {
return err
}
Expand Down Expand Up @@ -198,7 +198,7 @@ func (ng *nodegroup) Nodes() ([]cloudprovider.Instance, error) {
instances := make([]cloudprovider.Instance, len(nodes))
for i := range nodes {
instances[i] = cloudprovider.Instance{
Id: nodes[i],
Id: string(normalizedProviderString(nodes[i])),
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ func TestNodeGroupDeleteNodes(t *testing.T) {
})

for i := 0; i < len(nodeNames); i++ {
if nodeNames[i].Id != testConfig.nodes[i].Spec.ProviderID {
if nodeNames[i].Id != string(normalizedProviderString(testConfig.nodes[i].Spec.ProviderID)) {
t.Fatalf("expected %q, got %q", testConfig.nodes[i].Spec.ProviderID, nodeNames[i].Id)
}
}
Expand Down Expand Up @@ -722,7 +722,6 @@ func TestNodeGroupDeleteNodes(t *testing.T) {

func TestNodeGroupMachineSetDeleteNodesWithMismatchedNodes(t *testing.T) {
test := func(t *testing.T, expected int, testConfigs []*testConfig) {
t.Helper()
testConfig0, testConfig1 := testConfigs[0], testConfigs[1]
controller, stop := mustCreateTestController(t, testConfigs...)
defer stop()
Expand Down Expand Up @@ -756,7 +755,7 @@ func TestNodeGroupMachineSetDeleteNodesWithMismatchedNodes(t *testing.T) {
expectedErr0 = `node "test-namespace1-machineset-0-nodeid-0" doesn't belong to node group "test-namespace0/machinedeployment-0"`
}

if !strings.Contains(err0.Error(), expectedErr0) {
if !strings.Contains(err0.Error(), string(normalizedProviderString(expectedErr0))) {
t.Errorf("expected: %q, got: %q", expectedErr0, err0.Error())
}

Expand All @@ -771,7 +770,7 @@ func TestNodeGroupMachineSetDeleteNodesWithMismatchedNodes(t *testing.T) {
expectedErr1 = `node "test-namespace0-machineset-0-nodeid-0" doesn't belong to node group "test-namespace1/machinedeployment-0"`
}

if !strings.Contains(err1.Error(), expectedErr1) {
if !strings.Contains(err1.Error(), string(normalizedProviderString(expectedErr1))) {
t.Errorf("expected: %q, got: %q", expectedErr1, err1.Error())
}

Expand Down Expand Up @@ -845,7 +844,7 @@ func TestNodeGroupDeleteNodesTwice(t *testing.T) {
})

for i := 0; i < len(nodeNames); i++ {
if nodeNames[i].Id != testConfig.nodes[i].Spec.ProviderID {
if nodeNames[i].Id != string(normalizedProviderString(testConfig.nodes[i].Spec.ProviderID)) {
t.Fatalf("expected %q, got %q", testConfig.nodes[i].Spec.ProviderID, nodeNames[i].Id)
}
}
Expand Down
10 changes: 10 additions & 0 deletions cluster-autoscaler/cloudprovider/clusterapi/clusterapi_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package clusterapi

import (
"strconv"
"strings"

"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -48,6 +49,8 @@ var (
errInvalidMaxAnnotation = errors.New("invalid max annotation")
)

type normalizedProviderID string

// minSize returns the minimum value encoded in the annotations keyed
// by nodeGroupMinSizeAnnotationKey. Returns errMissingMinAnnotation
// if the annotation doesn't exist or errInvalidMinAnnotation if the
Expand Down Expand Up @@ -143,3 +146,10 @@ func machineSetIsOwnedByMachineDeployment(machineSet *MachineSet, machineDeploym
}
return false
}

// normalizedProviderString splits s on '/' returning everything after
// the last '/'.
func normalizedProviderString(s string) normalizedProviderID {
split := strings.Split(s, "/")
return normalizedProviderID(split[len(split)-1])
}
Original file line number Diff line number Diff line change
Expand Up @@ -369,3 +369,34 @@ func TestUtilMachineSetMachineDeploymentOwnerRef(t *testing.T) {
})
}
}

func TestUtilNormalizedProviderID(t *testing.T) {
for _, tc := range []struct {
description string
providerID string
expectedID normalizedProviderID
}{{
description: "nil string yields empty string",
providerID: "",
expectedID: "",
}, {
description: "empty string",
providerID: "",
expectedID: "",
}, {
description: "id without / characters",
providerID: "i-12345678",
expectedID: "i-12345678",
}, {
description: "id with / characters",
providerID: "aws:////i-12345678",
expectedID: "i-12345678",
}} {
t.Run(tc.description, func(t *testing.T) {
actualID := normalizedProviderString(tc.providerID)
if actualID != tc.expectedID {
t.Errorf("expected %v, got %v", tc.expectedID, actualID)
}
})
}
}

0 comments on commit cf4575f

Please sign in to comment.