-
Notifications
You must be signed in to change notification settings - Fork 346
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
Implement ExternalIPPool status #2490
Conversation
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.
My initial suggestion (and the scope of #2454) was to report usage data (number of allocated IPs vs total number of IPs). It seems that this PR wants to return a list of allocated IPs, which could lead to a significantly large Status. Is this PR trying to address something else besides #2454? It seems that it is missing some context, as there is no explanation of what Preallocated is compared to Allocated.
I don't know whether it needs to be consistent with IPPool status describing in #2442? I also think reporting usage data (number of allocated IPs vs total number of IPs) is better in ExternalIPPool status, this avoids a significantly large Status.
‘Preallocated’ represents the IP allocated to Egress but not assigned to Node yet. ‘Allocated’ represents the IP allocated to Egress and has been assigned to Node. If we report the status with a list of allocated IPs.
This PR is based on #2444, I was thinking rebase after merged, however they don't actually have dependencies. I will separate these two commits. |
9f3b3cd
to
c722aeb
Compare
Codecov Report
@@ Coverage Diff @@
## main #2490 +/- ##
==========================================
- Coverage 42.00% 41.98% -0.02%
==========================================
Files 153 154 +1
Lines 18565 18658 +93
==========================================
+ Hits 7798 7834 +36
- Misses 10067 10118 +51
- Partials 700 706 +6
Flags with carried forward coverage won't be shown. Click here to find out more.
|
pkg/controller/egress/controller.go
Outdated
"k8s.io/client-go/util/workqueue" | ||
"k8s.io/klog/v2" | ||
|
||
"antrea.io/antrea/pkg/apis/controlplane" | ||
egressv1alpha2 "antrea.io/antrea/pkg/apis/crd/v1alpha2" | ||
. "antrea.io/antrea/pkg/apis/crd/v1alpha2" |
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 not an encouraged usage, which misleads people that the types are in same package. Package qualifier is very useful to indicate where the dependency is. The code shouldn't pretend they are in same package which makes dividing them in different packages pointless.
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
This will then involve more components to achieve it and need a chain of reactions but I don't see much value it adds to the API. We already have enough information in Egress API about whether the Egress IP is just allocated or is configured on a Node. |
862daa8
to
7defc3e
Compare
As we discussed above, there is no need to keep the ExternalIPPool status consistent with IPPool status CRD. So I implemented the ExternalIPPool status with a new method which only reporting usage data (number of allocated IPs and total number of IPs). |
build/yamls/base/crds.yml
Outdated
type: object | ||
required: | ||
- used | ||
- total |
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: if they are set to "required", does it mean we must set it even when creating a new pool?
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.
Thanks for feedbacks. I have verified that it can work and create a ExternalIPPool successfully, It seems status.usage
is not required.
pkg/controller/egress/controller.go
Outdated
@@ -311,6 +315,37 @@ func (c *EgressController) setIPAllocation(egressName string, ip net.IP, poolNam | |||
} | |||
} | |||
|
|||
func (c *EgressController) updateExternalIPPoolStatus(poolName string, total, used int) error { |
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 method can be called concurrently in pool's eventHandler and egress's workers. So it seems that a race condition can make they override each other and the final value in API may be wrong. Maybe creating multiple Egresses can reproduce it.
If this is true, I would suggest have dedicated workers to sync pool's status, other places only enqueue a pool that needs to sync.
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.
Good consideration. Will reproduce and fix it.
7defc3e
to
4762b45
Compare
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 overall, some minor comments
pkg/controller/egress/controller.go
Outdated
@@ -92,6 +95,8 @@ type EgressController struct { | |||
egressGroupStore storage.Interface | |||
// queue maintains the EgressGroup objects that need to be synced. | |||
queue workqueue.RateLimitingInterface | |||
// queueEIP maintains the ExternalIPpool objects that need to be synced. | |||
queueEIP workqueue.RateLimitingInterface |
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.
It's more natural to call it eipQueue, but I think poolQueue is better.
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
test/e2e/egress_test.go
Outdated
@@ -311,6 +311,10 @@ func testEgressCRUD(t *testing.T, data *TestData) { | |||
require.NoError(t, err, "Failed to check if IP exists on Node") | |||
assert.False(t, exists, "Found stale IP on Node") | |||
} | |||
pool, err = data.crdClient.CrdV1alpha2().ExternalIPPools().Get(context.TODO(), pool.Name, metav1.GetOptions{}) | |||
assert.NoError(t, err) |
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.
assert.NoError(t, err) | |
require.NoError(t, err) |
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
test/e2e/egress_test.go
Outdated
pool, err = data.crdClient.CrdV1alpha2().ExternalIPPools().Get(context.TODO(), pool.Name, metav1.GetOptions{}) | ||
assert.NoError(t, err) | ||
assert.Equal(t, 1, pool.Status.Usage.Used, "ExternalIPPool status length not match") | ||
t.Logf("pool %s status: %v", pool.Name, pool.Status) |
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.
t.Logf("pool %s status: %v", pool.Name, pool.Status) | |
t.Logf("ExternalPool %s status: %v", pool.Name, pool.Status) |
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
test/e2e/egress_test.go
Outdated
@@ -311,6 +311,10 @@ func testEgressCRUD(t *testing.T, data *TestData) { | |||
require.NoError(t, err, "Failed to check if IP exists on Node") | |||
assert.False(t, exists, "Found stale IP on Node") | |||
} | |||
pool, err = data.crdClient.CrdV1alpha2().ExternalIPPools().Get(context.TODO(), pool.Name, metav1.GetOptions{}) | |||
assert.NoError(t, err) | |||
assert.Equal(t, 1, pool.Status.Usage.Used, "ExternalIPPool status length not match") |
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.
Maybe you can add expectedTotal
to the table and check it too.
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
pkg/controller/egress/controller.go
Outdated
@@ -24,12 +24,14 @@ import ( | |||
"sync" | |||
"time" | |||
|
|||
apimachineryerrors "k8s.io/apimachinery/pkg/api/errors" |
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: apierrors
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
4762b45
to
a27418f
Compare
pkg/controller/egress/controller.go
Outdated
@@ -92,6 +95,8 @@ type EgressController struct { | |||
egressGroupStore storage.Interface | |||
// queue maintains the EgressGroup objects that need to be synced. | |||
queue workqueue.RateLimitingInterface | |||
// poolQueue maintains the ExternalIPpool objects that need to be synced. |
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.
// poolQueue maintains the ExternalIPpool objects that need to be synced. | |
// poolQueue maintains the ExternalIPPool objects that need to be synced. |
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
db3126f
to
fe38f58
Compare
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. @antoninbas do you want to take a look since you suggested the enhancement?
/test-all |
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, thanks for working on this
// The current status of the ExternalIPPool. | ||
Status ExternalIPPoolStatus `json:"status"` |
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.
@tnqn we don't need omitempty
for this? I know that when kubebuilder generates CRD types, it always adds the omitempty
tag for the Status
field.
I also see it for upstream resources (at least for Pod
)
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.
It seems that there is no omitempty
tag for all the Status
field in the project. I think we can take another PR to implement it? @antoninbas @tnqn
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.
Although it's set for many Status
fields of native Kubernetes resources, I just found it doesn't have any impact as long as the field is a customized struct. I tried marshalling an empty ExternalIPPool
, it got the same result regardless of omitempty
is set:
{
"metadata": {
"creationTimestamp": null
},
"spec": {
"ipRanges": null,
"nodeSelector": {}
},
"status": {
"usage": {
"total": 0,
"used": 0
}
}
}
According to https://golang.google.cn/pkg/encoding/json/#Marshal, it works for the built-in types only.
The "omitempty" option specifies that the field should be omitted from the encoding if the field has an empty value, defined as false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or 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.
Thanks for confirming guys.
if gotEgress.Spec.ExternalIPPool != "" && gotEgress.Spec.EgressIP != "" { | ||
poolName := gotEgress.Spec.ExternalIPPool | ||
eip, err := controller.crdClient.CrdV1alpha2().ExternalIPPools().Get(context.TODO(), poolName, metav1.GetOptions{}) | ||
assert.NoError(t, err) |
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.
assert.NoError(t, err) | |
require.NoError(t, err) |
assert
will continue with the test, even though eip
will be nil
in case of an error
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
eip, err := controller.crdClient.CrdV1alpha2().ExternalIPPools().Get(context.TODO(), poolName, metav1.GetOptions{}) | ||
assert.NoError(t, err) | ||
usage := eip.Status.Usage | ||
assert.Equal(t, 1, usage.Used, fmt.Sprintf("ExternalIPPool status not match: %v", usage)) |
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.
assert.Equal(t, 1, usage.Used, fmt.Sprintf("ExternalIPPool status not match: %v", usage)) | |
assert.Equal(t, 1, usage.Used, "Expected one used IP in EgressIPPool Status") | |
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
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
/test-all |
@wenqiq e2e failed:
|
Fixed ExternalIPPool status checking logic order in Egress e2e test case. |
Report the number of allocated versus free IPs to the status of the Egress ExternalIPPool. For example: kubectl get eip ``` NAME TOTAL USED AGE eip-test-ipv4 345 1 20s ``` kubectl get eip -o yaml ``` ... items: - apiVersion: crd.antrea.io/v1alpha2 kind: ExternalIPPool ... spec: ipRanges: - end: 10.10.10.100 start: 10.10.10.10 status: usage: total: 91 used: 1 ... ``` Signed-off-by: Wenqi Qiu <wenqiq@vmware.com>
dfe2676
to
235022d
Compare
/test-all |
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
All the e2e test failures are unrelated to this PR: see #2618 |
Implement ExternalIPPool status
Report the number of allocated versus free IPs to the status of the Egress ExternalIPPool.
For example:
kubectl get eip
kubectl get eip -o yaml
For #2454