-
Notifications
You must be signed in to change notification settings - Fork 202
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes to support IPv6 addresses on nodes #268
Conversation
Hi @sdmodi. Thanks for your PR. I'm waiting for a kubernetes member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
/cc @basantsa1989 |
@sdmodi: GitHub didn't allow me to request PR reviews from the following users: basant1989. Note that only kubernetes members and repo collaborators can review this PR, and authors cannot review their own PRs. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
/ok-to-test |
/test cloud-provider-gcp-e2e-full |
Joe/Jiahui would you please review this. Thanks! |
/test cloud-provider-gcp-e2e-full |
/assign @bowei |
providers/gce/gce.go
Outdated
@@ -392,6 +397,10 @@ func generateCloudConfig(configFile *ConfigFile) (cloudConfig *CloudConfig, err | |||
cloudConfig.SecondaryRangeName = configFile.Global.SecondaryRangeName | |||
} | |||
|
|||
if configFile != nil && configFile.Global.StackType != "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can skip this check and let it set it to "" anyway?
providers/gce/gce_instances.go
Outdated
@@ -116,6 +118,27 @@ func (g *Cloud) NodeAddresses(ctx context.Context, nodeName types.NodeName) ([]v | |||
} | |||
nodeAddresses = append(nodeAddresses, v1.NodeAddress{Type: v1.NodeInternalIP, Address: internalIP}) | |||
|
|||
if g.stackType == "IPV4_IPV6" { | |||
// Handling only the internal v6 address. External v6 addresses will be handled once vendor apis are updated. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should remove or update this comment now that we support external too.
providers/gce/gce_instances.go
Outdated
if internalIPV6 != "" { | ||
nodeAddresses = append(nodeAddresses, v1.NodeAddress{Type: v1.NodeInternalIP, Address: internalIPV6}) | ||
} else { | ||
klog.Warningf("internal IPV6 range is empty") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle the external IPV6 addresses right here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to. Both the internal and external IPv6 addresses are written to this same field in the metadata.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool!
Nit: Rename 'internalIPV6s' and 'internalIPV6Arr' to something generic like ipv6s, ipv6Arr.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we include the node name in the warning log - might be helpful when debugging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Done.
} | ||
|
||
return nodeAddresses, nil | ||
} | ||
|
||
func getIPV6AddressFromInterface(nic *computealpha.NetworkInterface) string { | ||
ipv6Addr := nic.Ipv6Address | ||
if ipv6Addr == "" && nic.Ipv6AccessType == "EXTERNAL" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a discussion by gce team on supporting both public and private v6 IPs on the same interface. We may have to revisit this if that is the case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. For now, VMs just get one IPv6 address.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question about the access type - does "INTERNAL" correspond to directpath? What happen if the customer enables both dualstack and directpath?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
INTERNAL does not directly correspond to directpath. INTERNAL means that the subnet has only private IPv6 addresses. Today directpath uses INTERNAL addresses. When dual stack is enabled with directpath on a subnet with INTERNAL addresses, everything just works. Directpath and dual stack use the same IPs. Directpath on subnets with EXTERNAL addresses is not working currently. The GCE team is trying to figure something out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, thanks for the clarification. Make sense, seems like we will worry about the directpath use case later then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed the other comments
providers/gce/gce_instances.go
Outdated
if internalIPV6 != "" { | ||
nodeAddresses = append(nodeAddresses, v1.NodeAddress{Type: v1.NodeInternalIP, Address: internalIPV6}) | ||
} else { | ||
klog.Warningf("internal IPV6 range is empty") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to. Both the internal and external IPv6 addresses are written to this same field in the metadata.
} | ||
|
||
return nodeAddresses, nil | ||
} | ||
|
||
func getIPV6AddressFromInterface(nic *computealpha.NetworkInterface) string { | ||
ipv6Addr := nic.Ipv6Address | ||
if ipv6Addr == "" && nic.Ipv6AccessType == "EXTERNAL" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. For now, VMs just get one IPv6 address.
/test cloud-provider-gcp-verify-all |
1 similar comment
/test cloud-provider-gcp-verify-all |
There is a govet error
|
sent a PR to fix that #269 |
providers/gce/gce.go
Outdated
@@ -166,6 +166,9 @@ type Cloud struct { | |||
s *cloud.Service | |||
|
|||
metricsCollector loadbalancerMetricsCollector | |||
// stackType indicates whether the cluster is a single stack IPv4, single | |||
// stack IPv6 or a dual stack cluster | |||
stackType string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we have the list of all possible values as constants? something like
type StackType string
const NetworkStackDualStack StackType = "IPV4_IPV6"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This way we can eliminate the magic number below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
597be0f
to
8e0bf35
Compare
I wonder if there is a way to test this part of code right now. There is a |
I thought through how we could test this. The real issue is that the underlying code calls the metadata server which does not have the right architecture to fake. I can add tests for the part of the code that calls GCP API. Let me take a stab at doing that. Thanks! |
I have added unit tests wherever I could. Please take a look. @basantsa1989 would you please review this again. Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/lgtm
Kudos on the test coverage :)
providers/gce/gce_instances.go
Outdated
@@ -117,6 +119,27 @@ func (g *Cloud) NodeAddresses(ctx context.Context, nodeName types.NodeName) ([]v | |||
} | |||
nodeAddresses = append(nodeAddresses, v1.NodeAddress{Type: v1.NodeInternalIP, Address: internalIP}) | |||
|
|||
if g.stackType == NetworkStackDualStack { | |||
// Both internal and external IPv6 addresses are written to this array | |||
internalIPV6s, err := metadata.Get(fmt.Sprintf(networkInterfaceIPV6, nic)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Since we handle both internal and external IPv6 addresses, we can rename 'internalIPV6s' and 'internalIPV6Arr' to something generic like ipv6s, ipv6Arr.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@basantsa1989: changing LGTM is restricted to collaborators In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
lgtm for the change to the cloud provider. I do not have enough expertise with networking, though. |
/assign @MrHohn Zihong, would you please take a look at these changes from a networking point of view. Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got a few questions on the stacktype but overall LGTM.
@@ -393,6 +404,10 @@ func generateCloudConfig(configFile *ConfigFile) (cloudConfig *CloudConfig, err | |||
cloudConfig.SecondaryRangeName = configFile.Global.SecondaryRangeName | |||
} | |||
|
|||
if configFile != nil { | |||
cloudConfig.StackType = configFile.Global.StackType |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would be the default value for this StackType
field? Is empty the same as IPV4
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should treat empty the same as IPV4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep seems good. Was thinking what would happen when using this with old clusters.
providers/gce/gce_instances.go
Outdated
if internalIPV6 != "" { | ||
nodeAddresses = append(nodeAddresses, v1.NodeAddress{Type: v1.NodeInternalIP, Address: internalIPV6}) | ||
} else { | ||
klog.Warningf("internal IPV6 range is empty") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we include the node name in the warning log - might be helpful when debugging.
} | ||
|
||
return nodeAddresses, nil | ||
} | ||
|
||
func getIPV6AddressFromInterface(nic *computealpha.NetworkInterface) string { | ||
ipv6Addr := nic.Ipv6Address | ||
if ipv6Addr == "" && nic.Ipv6AccessType == "EXTERNAL" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question about the access type - does "INTERNAL" correspond to directpath? What happen if the customer enables both dualstack and directpath?
@@ -94,6 +94,12 @@ var _ cloudprovider.Zones = (*Cloud)(nil) | |||
var _ cloudprovider.PVLabeler = (*Cloud)(nil) | |||
var _ cloudprovider.Clusters = (*Cloud)(nil) | |||
|
|||
type StackType string | |||
|
|||
const NetworkStackDualStack StackType = "IPV4_IPV6" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there a reference from where this constant is coming from
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are in the comments of the go sdk.
https://pkg.go.dev/google.golang.org/api@v0.56.0/compute/v0.alpha
(search for "IPV4_IPV6")
Unfortunately the generated code did not have the constants directly avaliable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is actually being set by the GKE cluster server. This value is going to be written to gce.conf.
These changes populate the Node object with the IPv6 address as well as the IPv6 podCIDR. This is done only for clusters with stackType as IPV4_IPV6
} | ||
|
||
return nodeAddresses, nil | ||
} | ||
|
||
func getIPV6AddressFromInterface(nic *computealpha.NetworkInterface) string { | ||
ipv6Addr := nic.Ipv6Address | ||
if ipv6Addr == "" && nic.Ipv6AccessType == "EXTERNAL" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, thanks for the clarification. Make sense, seems like we will worry about the directpath use case later then.
@@ -393,6 +404,10 @@ func generateCloudConfig(configFile *ConfigFile) (cloudConfig *CloudConfig, err | |||
cloudConfig.SecondaryRangeName = configFile.Global.SecondaryRangeName | |||
} | |||
|
|||
if configFile != nil { | |||
cloudConfig.StackType = configFile.Global.StackType |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep seems good. Was thinking what would happen when using this with old clusters.
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: basantsa1989, MrHohn, sdmodi The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
/lgtm |
A recent change kubernetes#268 introduced IPv6 support, but it also began to require Google Cloud Compute Aplha API access. Unfortunately by default projects don't have this access and therefore, when the CCM fails with: googleapi: Error 403: Required 'Alpha Access' permission for 'Compute API', forbidden This commit starts using Alpha API only for dual stack deployments, where it's really required. For all other cases we will continue to use GA API. Fixes: kubernetes#281
kubernetes#268 introduced IPv6 support, but it also began to require Google Cloud Compute Aplha API access. Unfortunately by default projects don't have this access and therefore, when the CCM fails with: googleapi: Error 403: Required 'Alpha Access' permission for 'Compute API', forbidden This commit starts using Alpha API only for dual stack deployments, where it's really required. For all other cases we will continue to use GA API. Fixes: kubernetes#281
kubernetes#268 introduced IPv6 support, but it also began to require Google Cloud Compute Aplha API access. Unfortunately by default projects don't have this access and therefore, when the CCM fails with: googleapi: Error 403: Required 'Alpha Access' permission for 'Compute API', forbidden This commit starts using Alpha API only for dual stack deployments, where it's really required. For all other cases we will continue to use GA API. Fixes: kubernetes#281
kubernetes#268 introduced IPv6 support, but it also began to require Google Cloud Compute Aplha API access. Unfortunately by default projects don't have this access and therefore, when the CCM fails with: googleapi: Error 403: Required 'Alpha Access' permission for 'Compute API', forbidden This commit starts using Alpha API only for dual stack deployments, where it's really required. For all other cases we will continue to use GA API. Fixes: kubernetes#281
kubernetes#268 introduced IPv6 support, but it also began to require Google Cloud Compute Aplha API access. Unfortunately by default projects don't have this access and therefore, when the CCM fails with: googleapi: Error 403: Required 'Alpha Access' permission for 'Compute API', forbidden This commit starts using Alpha API only for dual stack deployments, where it's really required. For all other cases we will continue to use GA API. Fixes: kubernetes#281
kubernetes#268 introduced IPv6 support, but it also began to require Google Cloud Compute Aplha API access. Unfortunately by default projects don't have this access and therefore, when the CCM fails with: googleapi: Error 403: Required 'Alpha Access' permission for 'Compute API', forbidden This commit starts using Alpha API only for dual stack deployments, where it's really required. For all other cases we will continue to use GA API. Fixes: kubernetes#281
kubernetes#268 introduced IPv6 support, but it also began to require Google Cloud Compute Aplha API access. Unfortunately by default projects don't have this access and therefore, when the CCM fails with: googleapi: Error 403: Required 'Alpha Access' permission for 'Compute API', forbidden This commit starts using Alpha API only for dual stack deployments, where it's really required. For all other cases we will continue to use GA API. Fixes: kubernetes#281
These changes populate the Node object with the IPv6 address as well as the IPv6 podCIDR. This is done only for clusters with stackType as IPV4_IPV6. This patch handles both the internal and external IPv6 addresses.