Skip to content

Conversation

@vakalapa
Copy link
Contributor

@vakalapa vakalapa commented Apr 30, 2021

This PR is fix the bug of supporting multiple values in a LabelSelector match expressions.

 - key: pod
    operator: In
    values:
      - b
      - c

Today NPM considers the values of the above selector to be b AND c, but it should be b OR c

NPM now follows different design for podSelector and nameSpaceSelector.

For PodSelector, NPM has ipsets with immutable members like ips or ip,proto:port. Ipset allows creating 2nd level ipset ype list:set to be created with pod label ipsets as members and NPM will use this 2nd level ipset as the matchset criteria in rules.

For NameSpaceSelector, NPM uses ipsets with mutable members like other ipsets. Ipset does not allow adding list:set as members to list:set ipset, so 2nd level ipset cannot be used in case of nameSelectors. For this reason NPM will create combinations of nameSpaceSelectors and add individual rule for each combination.

@vakalapa vakalapa added bug npm Related to NPM. labels Apr 30, 2021
@vakalapa vakalapa marked this pull request as ready for review May 5, 2021 02:11
@vakalapa
Copy link
Contributor Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

return []metav1.LabelSelector{*nsSelector}
}

// Now use the baseSelector and loop over multiValueMatchExprs to create all
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Highly suggest moving codes from 185-192 to "zipMatchExprs". It will improve readability. Now, I need to track for loop in 190 with zipMatchExprs function which uses returned values as input again.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or moving codes from "zipMatchExprs" to here. The function name of "zipMatchExprs" is not very intuitive at least to me. I think "FlattenNameSpaceSelector" function has a good name and combining all codes in the function is good to understand and not deep.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I modelled it as a recursive function, where we take in a slice and expand it using each expr.

for i, _ := range nsLabelsWithoutOps {
// Add namespaces prefix to distinguish namespace ipset lists and pod ipsets
nsLabelsWithoutOps[i] = "ns-" + nsLabelsWithoutOps[i]
for _, nsSelector := range FlattenNameSpaceSelector(fromRule.NamespaceSelector) {
Copy link
Contributor

@JungukCho JungukCho May 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer to splitting this one line to two lines to understand what it returns. Same to all in this file, but not strong opinion.

// for _, egressRule := range nsSelector {
// log.Logf("%+v", egressRule)
// }
/*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure we need these long comments. I think it was well explained in comments (140-142) and is better to add concise explanation in the comments (140-142) based on summary of these long comments.
For example, matchExpressions "ns in (netpol-x, netpol-y)" is converted to multiple matchExpressions [
"ns in (netpol-x)", "ns in (netpol-y)"], then translate policy will replicate each of these nsSelectors to add two different rules in iptables, resulting in OR condition between the values.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comes back to what we discussed in our meeting today, having a visual representation of what the YAML looks like and what the transformation looks like will help other developers to quickly understand. I would like to keep this as is if its ok.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, I suggested putting comprehensive information (e.g., pods yaml and netpol yaml which shows the problem in our NPM) to reproduce the problem, which helps to understand big picture at the first. T
his code is very straightforward. So, I don't think we need this, but if you want to keep it, I don't have strong opinion.

t.Errorf("TestFlattenNameSpaceSelector failed @ 2nd selector length check %+v", testSelectors)
}

expectedSelectors := []metav1.LabelSelector{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can make these tests concise and simple for all unit tests in this function and improve readability as well.
There are many things are repeated (e.g., LabelSelectorRequirement and MatchLabels).
We can make it better. One example is below.

matchLabels := map[string]string{
				"c": "d",
				"a": "b",
			}
then use matchLabels whenever creating &metav1.LabelSelector.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a common matchLabel to help with readability

t.Errorf("TestFlattenNameSpaceSelector failed @ 1st selector length check %+v", testSelectors)
}

if !reflect.DeepEqual(testSelectors[0], *firstSelector) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are multiple time to check length of returned values from FlattenNameSpaceSelector and deepEqual in this function and TestFlattenNameSpaceSelectorWoMatchLabels function. So, I think it is better to make one helper function to check them together.

Copy link
Contributor Author

@vakalapa vakalapa Jul 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. but they are only a couple and i feel the code is self explanatory in itself,

}

func TestFlattenNameSpaceSelectorWoMatchLabels(t *testing.T) {
firstSelector := &metav1.LabelSelector{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. You can make it concise and better readability by using variables to avoid unnecessary repeat.

if err = ipsMgr.CreateList(listKey); err != nil {
return fmt.Errorf("[syncAddAndUpdateNetPol] Error: creating ipset list %s with err: %v", listKey, err)
}
ipsMgr.IpSetReferIncOrDec(listKey, util.IpsetSetListFlag, ipsm.IncrementOp)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, I prefer to having another function which functions "CreateList and IPSetReferIncOrDec". It will be easy to remember and help to encapsulate details.
I assume that your next PR is about those reference counts, we can revisit this in the PR.

return nil
}

// Clean removes all the empty sets & lists under the namespace.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When do we use this function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean() function is not being currently, this is for future work items.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest not to add function which is not used in this PR. I think this is a good practice.
There are multiple reasons.

  1. Reviewer do not need to spend time.
  2. Add the function with the PR for your future work items. So, it will be well aligned and easy to understand PR.
  3. There are possibility that this function will not be used in the future. At that time, this function just stays for long time.

I think you have future work item to use this function. So, add this function in the PR.


// IpSetReferIncOrDec checks if an element exists in setMap/listMap and then increases or decreases tis refer count.
// IpSetReferIncOrDec checks if an element exists in setMap/listMap and then increases or decreases this referCount.
func (ipsMgr *IpsetManager) IpSetReferIncOrDec(ipsetName string, kind string, countOperation ReferCountOperation) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have plan to extend this function for other types in addition to "list" as well?
In this PR, kind is always "list".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes in the next work item(refer coutn) we will extend support of this IncDec to SetMap where we will track the use of iptable rules and their references to a given ipset. we will track both kinds of ipsets.

JungukCho
JungukCho previously approved these changes Jul 2, 2021
Copy link
Contributor

@JungukCho JungukCho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for applying comments. Look forward to your next PR.

@vakalapa
Copy link
Contributor Author

vakalapa commented Jul 7, 2021

@vakalapa vakalapa merged commit a1b487a into master Jul 7, 2021
@vakalapa vakalapa deleted the vakr/k8smultiparse branch July 7, 2021 16:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug npm Related to NPM.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NetworkPolicy should enforce policy based on Multiple PodSelectors and NamespaceSelector

4 participants