-
Notifications
You must be signed in to change notification settings - Fork 260
[NPM] 🐞 {fix} error creating IPsets when same string for ports and labels is used #734
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
Conversation
npm/pod_test.go
Outdated
| if err := npMgr.AddPod(podObj); err != nil { | ||
| t.Errorf("TestAddPod failed @ AddPod") | ||
| } | ||
| if !ipsMgr.Exists(util.GetHashedName("app:test-pod"), "1.2.3.4,8080", "") { |
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.
Will it be port:app:test-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.
Yes thank you.
Codecov Report
@@ Coverage Diff @@
## master #734 +/- ##
==========================================
+ Coverage 39.06% 39.36% +0.29%
==========================================
Files 83 83
Lines 10713 10827 +114
==========================================
+ Hits 4185 4262 +77
- Misses 6022 6061 +39
+ Partials 506 504 -2 |
npm/npm.go
Outdated
| iptMgr.UninitNpmChains() | ||
|
|
||
| log.Logf("Azure-NPM creating, cleaning existing IPSets") | ||
| destroyErr := ipsm.NewIpsetManager().Destroy() |
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.
Wont this cleanup all the ipsets from that node? We should only clean the ones created by Azure-NPM. Also ignore the error as this is best effort to clean the old ipsets.
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.
As we discussed offline, NPM is not saving state any state while updating, to avoid any leak of ipsets, we will destroy everything. I logged a work item to add state fullness to this logic.
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.
Agree with Neha here, an ipset flush wipes out all ipsets, including ones NPM may have not created, this is where we need to iterate through all ipsets that contain azure-npm
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.
Added support to just delete azure-npm-(numerics) ipsets and lists
npm/util/const.go
Outdated
| IpsetNomatch string = "nomatch" | ||
|
|
||
| //Prefixes for ipsets | ||
| NamedPortIPSetPrefix string = "port:" |
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 rename the value from port: to portname: (or namedport:):, port seems very common
| for _, portRule := range rule.Ports { | ||
| if portRule.Port != nil && portRule.Port.IntValue() == 0 { | ||
| portName := portRule.Port.String() | ||
| portName := util.NamedPortIPSetPrefix + portRule.Port.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 confirm this? We can still have a port rule without a named port, right?
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.
Okay checked the logic, all port strings are getting appending to Namedports and in the end we call util.DropEmptyFields(namedPorts) (Line: 1438). This is weird. But with the updated logic empty port strings will not be dropped. We should only add if portRule.port.String() is not empty. This should have been the logic at first place instead of double parsing :-/
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 still add a test with policy which has port rules (without named ports) and one without
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.
NPM is allowing this below network policy, corrected the behavior now.
ingress:
- from:
- podSelector:
matchLabels:
app: backend
ports:
- port: ""
neaggarwMS
left a comment
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.
Left minor comments, rest looks good.
npm/ipsm/ipsm.go
Outdated
| entry.operationFlag = util.IpsetDestroyFlag | ||
| entry.set = ipsetName | ||
| if _, err := ipsMgr.Run(entry); err != nil { | ||
| metrics.SendErrorMetric(util.IpsmID, "Error: failed to destroy ipset %s", ipsetName) |
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 you add the FunctionName in the log statement for better debugability: DestroyNpmIpsets (We dont print the FileName/Line# in the Geneva output, although we should.)
npm/ipsm/ipsm.go
Outdated
|
|
||
| if _, err := ipsMgr.Run(entry); err != nil { | ||
| metrics.SendErrorMetric(util.IpsmID, "Error: failed to flush ipset %s", ipsetName) | ||
| log.Logf("Error: failed to flush ipset %s", ipsetName) |
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.
SendErrorMetric also logs the error. Actually that is an incorrect functionName it should be SendErrorLog or SendLog
npm/ipsm/ipsm.go
Outdated
| entry.set = ipsetName | ||
| if _, err := ipsMgr.Run(entry); err != nil { | ||
| metrics.SendErrorMetric(util.IpsmID, "Error: failed to destroy ipset %s", ipsetName) | ||
| log.Logf("Error: failed to destroy ipset %s", ipsetName) |
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.
Again remove the duplicate logF line
npm/translatePolicy.go
Outdated
| } | ||
|
|
||
| func getPortType(portRule networkingv1.NetworkPolicyPort) string { | ||
| if portRule.Port == nil { |
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: We can combine 1st and last check
if portRule.Port == nil || portRule.Port.IntValue() != 0
{
return "validport"
} else ...
npm/npm.go
Outdated
| log.Logf("Azure-NPM creating, cleaning existing Azure NPM IPSets") | ||
| destroyErr := ipsm.NewIpsetManager().DestroyNpmIpsets() | ||
| if destroyErr != nil { | ||
| log.Logf("Azure-NPM error occurred while destroying existing IPSets err: %s", destroyErr.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.
nit, wondering, if DestroyNpmIpsets did metrics.SendErrorMetric inside its function, whether do we want to log here again.
npm/ipsm/ipsm.go
Outdated
| for _, matchedItem := range ipsetRegexSlice { | ||
| if len(matchedItem) == 2 { | ||
| itemString := string(matchedItem[1]) | ||
| if strings.Contains(itemString, "azure-npm") { |
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, do we want to use a const for "azure-npm"
|
|
||
| func getPortType(portRule networkingv1.NetworkPolicyPort) string { | ||
| if portRule.Port == nil || portRule.Port.IntValue() != 0 { | ||
| return "validport" |
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 make these consts in case we end up using this elsewhere?
Reason for Change:
NPM creates IPsets for the following today:
Namespace and namespace labels are getting a
ns-prefix helping NPM to distinguish between PodLabels and NameSpaceLabels. But there are several instances where the IPSet names for Labels and NamedPorts are surfacing. This occurs when a podLabelhttp:testand a namedPorthttpis created. An example can be seen in #733 . NPM hasheshttpfrom label and creates a IpSet with this hash, then when it is adding namedPorthttpit would hash to the same value and it logs this below error.Using ":" as prefix delimiter as k8s does not allow using a ":" in label names.
Issue Fixed:
#733
Further Enhancements
Name clash probability is still high. Work item is added to have a robust logic while adding IpSets