Change:
When adding to kubelet and to the OpenStack external cloud provider, which is based on kubernetes v1.27.1, the node annotation only shows one address and consequently the node addresses also only displays one address. The kubelet logs shows that node-ip contains dual-stack addresses. The annotation on the node would contain both IPv4 and IPv6 addresses and the node addresses would list them. Deploy a cluster with to kubelet and external cloud provider. Also make sure the external cloud provider is based on Kubernetes 1.27. Kubelet logs: one of CCMs Pods: one of the nodes annotation: <details</details<details</details<details</details<details</details<details</details<details</details
/sig network /sig cloud-provider /cc
/assign
/triage accepted

Discussion:
if node.ObjectMeta.Annotations == nil { node.ObjectMeta.Annotations = make(map[string]string) } <del> node.ObjectMeta.Annotations[cloudproviderapi.AnnotationAlphaProvidedIPAddr] = nodeIP.String() </del> <ins> annotation := nodeIP.String() if secondaryNodeIPSpecified { annotation += "," + secondaryNodeIP.String() } node.ObjectMeta.Annotations[cloudproviderapi.AnnotationAlphaProvidedIPAddr] = annotation </ins> } else if node.ObjectMeta.Annotations != nil { // Clean up stale annotations if no longer using a cloud provider or // no longer overriding node IP.

name                           string hostnameOverride               bool nodeIP                         net.IP <ins> secondaryNodeIP                net.IP </ins> cloudProviderType              cloudProviderType nodeAddresses                  []v1.NodeAddress expectedAddresses              []v1.NodeAddress

}, shouldError: false, }, <ins> { // We don't have to test "legacy cloud provider with dual-stack // IPs" etc because we won't have gotten this far with an invalid // config like that. name:              "Dual-stack cloud, with dual-stack nodeIPs", nodeIP:            netutils.ParseIPSloppy("2600:1f14:1d4:d101::ba3d"), secondaryNodeIP:   netutils.ParseIPSloppy("10.1.1.2"), cloudProviderType: cloudProviderExternal, nodeAddresses: []v1.NodeAddress{ {Type: v1.NodeInternalIP, Address: "10.1.1.1"}, {Type: v1.NodeInternalIP, Address: "10.1.1.2"}, {Type: v1.NodeInternalIP, Address: "2600:1f14:1d4:d101::ba3d"}, {Type: v1.NodeHostName, Address: testKubeletHostname}, }, expectedAddresses: []v1.NodeAddress{ {Type: v1.NodeInternalIP, Address: "2600:1f14:1d4:d101::ba3d"}, {Type: v1.NodeInternalIP, Address: "10.1.1.2"}, {Type: v1.NodeHostName, Address: testKubeletHostname}, }, expectedAnnotations: map[string]string{ "alpha.kubernetes.io/provided-node-ip": "2600:1f14:1d4:d101::ba3d,10.1.1.2", }, shouldError: false, }, { name:              "Upgrade to cloud dual-stack nodeIPs", nodeIP:            netutils.ParseIPSloppy("10.1.1.1"), secondaryNodeIP:   netutils.ParseIPSloppy("2600:1f14:1d4:d101::ba3d"), cloudProviderType: cloudProviderExternal, nodeAddresses: []v1.NodeAddress{ {Type: v1.NodeInternalIP, Address: "10.1.1.1"}, {Type: v1.NodeInternalIP, Address: "2600:1f14:1d4:d101::ba3d"}, {Type: v1.NodeHostName, Address: testKubeletHostname}, }, expectedAddresses: []v1.NodeAddress{ {Type: v1.NodeInternalIP, Address: "10.1.1.1"}, {Type: v1.NodeInternalIP, Address: "2600:1f14:1d4:d101::ba3d"}, {Type: v1.NodeHostName, Address: testKubeletHostname}, }, existingAnnotations: map[string]string{ "alpha.kubernetes.io/provided-node-ip": "10.1.1.1", }, expectedAnnotations: map[string]string{ "alpha.kubernetes.io/provided-node-ip": "10.1.1.1,2600:1f14:1d4:d101::ba3d", }, shouldError: false, }, { name:              "Downgrade from cloud dual-stack nodeIPs", nodeIP:            netutils.ParseIPSloppy("10.1.1.1"), cloudProviderType: cloudProviderExternal, nodeAddresses: []v1.NodeAddress{ {Type: v1.NodeInternalIP, Address: "10.1.1.1"}, {Type: v1.NodeInternalIP, Address: "2600:1f14:1d4:d101::ba3d"}, {Type: v1.NodeHostName, Address: testKubeletHostname}, }, expectedAddresses: []v1.NodeAddress{ {Type: v1.NodeInternalIP, Address: "10.1.1.1"}, {Type: v1.NodeHostName, Address: testKubeletHostname}, }, existingAnnotations: map[string]string{ "alpha.kubernetes.io/provided-node-ip": "10.1.1.1,2600:1f14:1d4:d101::ba3d", }, expectedAnnotations: map[string]string{ "alpha.kubernetes.io/provided-node-ip": "10.1.1.1", }, shouldError: false, }, </ins> } for _, testCase := range cases { t.Run(testCase.name, func(t *testing.T) {

existingNode.Status.Addresses = append(existingNode.Status.Addresses, existingNodeAddress) } <del> nodeIP := testCase.nodeIP </del> nodeIPValidator := func(nodeIP net.IP) error { return nil }

} } <ins> nodeIPs := []net.IP{testCase.nodeIP} if testCase.secondaryNodeIP != nil { nodeIPs = append(nodeIPs, testCase.secondaryNodeIP) } </ins> // construct setter <del> setter := NodeAddress([]net.IP{nodeIP}, </del> <ins> setter := NodeAddress(nodeIPs, </ins> nodeIPValidator, hostname, testCase.hostnameOverride,