Conversation
78db510 to
afad54f
Compare
|
@eng-contiv |
afad54f to
d94ce81
Compare
6dc0038 to
b518659
Compare
tiewei
left a comment
There was a problem hiding this comment.
reviewed half of the changes. some suggestions
- logging on success request as well
- logging and avoid infinity loop
- transactional operation should be handled on server side, this way will avoid wired race condition and other concurrency issue
|
|
||
| const defaultTenantName = "default" | ||
| const defaultNetworkName = "net" | ||
| const defaultNetworkName = "default-net" |
There was a problem hiding this comment.
do we need to provide upgrading guide for this change ?
There was a problem hiding this comment.
Seems from earlier conversations, admin would need to create a "default-net" but would have to be a different subnet? Could that break some deployments? Requires network changes to pods and redeploy?
| return defaultEpgName | ||
| } | ||
| func getTenantInfo() string { | ||
| return defaultTenantName |
There was a problem hiding this comment.
why these 4 functions are required ?
There was a problem hiding this comment.
Initially thinking to use wrapper function to access default tenant and EPG name . look like currently not using it. will remove it
| nwName) | ||
| return err | ||
| }() != nil { | ||
| //XXX:Should we really poll here ; |
There was a problem hiding this comment.
if an infinity loop is here ( without enough logs and hints), no one would able to know how to find out.
please put logs and a maxretry here.
There was a problem hiding this comment.
idea: log first loop iteration
optionally, additionally we log every minute so we know there is an issue
| nwName) | ||
| return err | ||
| }() == nil { | ||
| }() == nil { //XXX: Same here as above |
| if _, err := k8sNet.contivClient.NetworkGet(defaultTenantName, nwName); err != nil { | ||
| if _, err := k8sNet.contivClient.NetworkGet( | ||
| defaultTenantName, | ||
| nwName); err != nil { |
There was a problem hiding this comment.
log the network deleted correctly
| if _, err := k8sNet.contivClient.NetworkGet(defaultTenantName, nwName); err == nil { | ||
| if _, err := k8sNet.contivClient.NetworkGet( | ||
| defaultTenantName, | ||
| nwName); err == nil { |
There was a problem hiding this comment.
to follow up, creating a network that is already there could be construed as a problem, would be good to log so that we can track it down when we have time, I know this was just a reformat
| epgName) | ||
| return err | ||
| }() != nil { | ||
| }() != nil { //XXX: Same as above |
| npLog.Errorf("failed to update EPG %v: err:%v ", epgName, err) | ||
| return err | ||
| } | ||
| k8sNet.epgName[epgName] = epgName |
There was a problem hiding this comment.
log default policy and default epg content
| //policy := k8sutils.EpgNameToPolicy(epgName, policyName) | ||
| if _, err := k8sNet.contivClient. | ||
| PolicyGet(tenantName, policyName); err == nil { | ||
| npLog.Infof("Policy:%v found contiv", policyName) |
There was a problem hiding this comment.
i think instead get-check-create, the creating checking operations should be handled on server side, this way will avoid concurrency issue
b518659 to
54c9c88
Compare
There was a problem hiding this comment.
haven't finished reviewing, however, the pod selector logic for pod selectors matchlabels should be AND and not OR:
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is “key”, the operator is “In”, and the values array contains only “value”. The requirements are ANDed.
https://kubernetes.io/docs/api-reference/v1.8/#labelselector-v1-meta
| } | ||
| type labelPolicySpec struct { | ||
| policy []*k8sNetworkPolicy | ||
| } |
There was a problem hiding this comment.
this struct is never referenced
| Port int | ||
| Protocol string | ||
| } | ||
| type k8sNameSelector struct { |
There was a problem hiding this comment.
if this is namespace selector, can we name the struct k8sNamespaceSelector?
| type k8sIngress struct { | ||
| IngressRules []k8sPolicyPorts | ||
| IngressPodSelector []*k8sPodSelector | ||
| IngressNameSelector *k8sNameSelector |
| type npPodInfo struct { | ||
| nameSpace string | ||
| labelSelectors []string | ||
| IP string //??? should care for ipv6 address |
| podEpg string | ||
| } | ||
| type k8sIPBlockSelector struct { | ||
| subNetIps []string |
There was a problem hiding this comment.
how is the "except" clause going to be handled? see in the docs an example:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
| //List of Rules Per Policy | ||
| // policyRules map[string][]string | ||
| //List of Network configured | ||
| network map[string]bool |
| //List of Network configured | ||
| network map[string]bool | ||
| //List of EPG configured as set | ||
| epgName map[string]bool |
| policyPerEpg map[string]map[string][]string | ||
| //Cache table for given Pods | ||
| //Policy Obj per Policy Name | ||
| nwPolicyPerNameSpace map[string][]*k8sNetworkPolicy |
There was a problem hiding this comment.
nwPoliciesPerNamespace (plural)
| return | ||
| //Get Network Policy object sets which ToSpec labelMap information match | ||
| //with given pods labelMap | ||
| func (k8sNet *k8sContext) getMatchToSpecPartNetPolicy( |
There was a problem hiding this comment.
This might be easier to unit test if you passed in the podInfo's namespace and labelSelectors values instead of the podInfo itself.
I had a hard time with this function name, could we rename with some hints for input, output, and more specific behavior?
e.g.: getPoliciesForPodByLabels
|
|
||
| if len(toPartPolicy) > 0 { | ||
| npLog.Infof("Recv Pod belongs to ToSpec part of Policy") | ||
| for _, nw := range toPartPolicy { |
There was a problem hiding this comment.
nw looks like a network, but this is a policy, please update the name?
chrisplo
left a comment
There was a problem hiding this comment.
getting closer to first pass complete! but having to rethink how I approach the review since it's so big, working through a top down code execution path review now so I can get some clarity on some implementation choices that have been made.
most of the feedback is minor naming / logging type stuff to help fresh eyes figure out what's going on, but there are a few real concerns sprinkled in
| return defaultTenantName | ||
| } | ||
|
|
||
| //Start Network Policy feature enabler |
There was a problem hiding this comment.
I know you didn't touch, but could you please log infon on first pass through he infinite sleep below?
| if _, err := k8sNet.contivClient.NetworkGet(defaultTenantName, nwName); err == nil { | ||
| if _, err := k8sNet.contivClient.NetworkGet( | ||
| defaultTenantName, | ||
| nwName); err == nil { |
There was a problem hiding this comment.
to follow up, creating a network that is already there could be construed as a problem, would be good to log so that we can track it down when we have time, I know this was just a reformat
| nwName) | ||
| return err | ||
| }() != nil { | ||
| //XXX:Should we really poll here ; |
There was a problem hiding this comment.
idea: log first loop iteration
optionally, additionally we log every minute so we know there is an issue
| if err = k8sNet.createDefaultPolicy( | ||
| defaultTenantName, | ||
| epgName); err != nil { | ||
| npLog.Errorf("failed Default ingress policy EPG %v: err:%v ", |
There was a problem hiding this comment.
failed creating? maybe could be more clear, default ingress policy for which network/tenant?
| return err | ||
| } | ||
| if err = k8sNet.createEpg(nwName, epgName, policy); err != nil { | ||
| npLog.Errorf("failed to update EPG %v: err:%v ", epgName, err) |
| k8sNet.parseIngressPolicy(np.Spec.Ingress, | ||
| np.Namespace) | ||
| if err != nil { | ||
| npLog.Warnf("ignore network policy: %s, %v", np.Name, err) |
There was a problem hiding this comment.
like above, maybe not "ignore"
| @@ -343,7 +750,7 @@ func (k8sNet *k8sContext) watchK8sEvents(errChan chan error) { | |||
| for k8sNet.isLeader() != true { | |||
| time.Sleep(time.Millisecond * 100) | |||
There was a problem hiding this comment.
marking a spot where we can use a logging retry function
| opCode watch.EventType, np *network_v1.NetworkPolicy) { | ||
| if np.Namespace == "kube-system" { //not applicable for system namespace | ||
| return | ||
| } |
There was a problem hiding this comment.
minor, but since both this and processK8sPod both do this check, you could do it in processK8sEvent instead?
|
|
||
| func (k8sNet *k8sContext) addNetworkPolicy(np *network_v1.NetworkPolicy) { | ||
| //check if given Policy already exist | ||
| if _, ok := k8sNet.networkPolicy[np.Name]; ok { |
There was a problem hiding this comment.
I'm not sure about the top level network policy map as I thought network policy names can be reused across namespaces
| } | ||
| type k8sNetworkPolicy struct { | ||
| PodSelector *k8sPodSelector | ||
| Ingress []k8sIngress |
There was a problem hiding this comment.
I think the policy name should be here instead of in the pod selector for instance
| PodSelector := k8sPodSelector{ | ||
| TenantName: getTenantInfo(), | ||
| NetworkName: getNetworkInfo(), | ||
| GroupName: getEpgInfo()} |
There was a problem hiding this comment.
these three look like placeholders for needed functionality, I think Ranjith's other PR I'm looking at (well I made my own PR based on his) might fit in here for the group name.
Let's discuss/see if we can get to wider consensus that mapping tenant to namespace make sense (thought I saw some conversations that this could be a really good mapping)
| for _, l := range label { | ||
| if ipMap, ok := | ||
| podSelector.labelPodMap[l]; ok { | ||
| ipMap[ip] = true |
There was a problem hiding this comment.
I think this might be a spot to adjust for the AND logic of the matchLabels
| nw *k8sNetworkPolicy, label []string, ip string) { | ||
| for _, ingress := range nw.Ingress { | ||
| for _, podSelector := range ingress.IngressPodSelector { | ||
| npLog.Infof("podSelector:%+v", podSelector) |
There was a problem hiding this comment.
leftover debug statement?
| //At each Label Walk all its Ips | ||
| for ip := range lMap { | ||
| nw.PodSelector.podIps[ip] = ip | ||
| } |
There was a problem hiding this comment.
another spot that might be implementing OR logic instead of AND logic for matchLabels
| if err = k8sNet.deleteRule(policyName, defaultRuleID); err != nil { | ||
| npLog.Errorf("failed to delete default rule, %s", err) | ||
| //Consolidate all Ips belongs to Label for Pod Selector object | ||
| func (k8sNet *k8sContext) updatePodSelectorPodIps( |
There was a problem hiding this comment.
this function doesn't appear to use k8sContext, be more appropriate to be part of the k8sPodSelector struct?
| func (k8sNet *k8sContext) initPodSelectorCacheTbl(m map[string]string, | ||
| podSelector *k8sPodSelector) error { | ||
| if podSelector == nil { | ||
| return fmt.Errorf("Passe Nil Pod Selector reference") |
There was a problem hiding this comment.
"Passed", though this is an internal method and we create the podselector in the caller, why would we expect this to ever be nil?
| for key, val := range pod.ObjectMeta.Labels { | ||
| lkey := getLabelSelector(key, val) | ||
| npLog.Infof("Update label Selector key:%v", lkey) | ||
| if ipMap, ok := PodSelector.labelPodMap[lkey]; ok { |
There was a problem hiding this comment.
marking a spot that I think is aligning with OR based logic for label matching instead of AND
| // reset policy to deny on any error | ||
| policyResetOnErr := func(tenantName, groupName string) { | ||
| if err != nil { | ||
| //k8sNet.resetPolicy(tenantName, groupName) |
There was a problem hiding this comment.
missing implementation, though this could be touchy, not sure we should back out of the existing working policy . . . we might want to focus more on reconciliation of policy against contiv resources for the next attempt
| //Get PolicyMap using EPG | ||
| policyMap := k8sNet.policyPerEpg[np.PodSelector.GroupName] | ||
| //Check if Policy is already programmed in EPG or not | ||
| if _, ok := k8sNet.networkPolicy[np.PodSelector.PolicyName]; !ok { |
There was a problem hiding this comment.
policy names I think can be repeated across namespaces, this datastructure would have false positives for existence
| if _, ok := k8sNet.networkPolicy[np.PodSelector.PolicyName]; !ok { | ||
| //Create Policy and published to ofnet controller | ||
| if err = k8sNet.createPolicy( | ||
| defaultTenantName, |
There was a problem hiding this comment.
shouldn't this be the podselector's tenant?
| } | ||
| //k8sNet.policyPerEpg[np.PodSelector.GroupName] = attachPolicy | ||
| } else { | ||
| //XXX: Need check if policy rules are still same or not |
There was a problem hiding this comment.
noting missing implementation
| policyName string) (lRules *[]client.Rule) { | ||
| var listRules []client.Rule | ||
| for _, ingress := range np.Ingress { | ||
| isPortsCfg := false |
There was a problem hiding this comment.
just initiaze the variable to the expression eval instead of separate if block?
| attachPolicy := []string{} | ||
| for policyN := range policyMap { | ||
| attachPolicy = append(attachPolicy, policyN) | ||
| } |
There was a problem hiding this comment.
append(attachPolicy, policyMap...) ?
| attachPolicy := []string{} | ||
| for policyN := range policyMap { | ||
| attachPolicy = append(attachPolicy, policyN) | ||
| } |
There was a problem hiding this comment.
append(attachPolicy, policyMap...) ? or even
attachPolicy := make([]string, len(policyMap))
copy(attachPolicy, policyMap)
54c9c88 to
531e319
Compare
Include default deny policy Policy cleanup code Pod Add/Delete event processing unit test cases fix fix core issue in pod delete fix core issue in pod delete some cleanup in existing code K8s Network Policy support code changes
|
After creating EPG, are the spec pods updated to belong to this EPG? If not,will the flow table of ovs install this policy? |
Description of the changes
This is feature commit to support K8s Network Policy at contiv. Using feature, Contiv will support K8s Ingress Network Policy however egress policy support comes in future code commit
Type of fix: New feature
Fixes #1089
Please describe:
= Create k8s Network Policy without configuring Pods
cat network-policy.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: access-nginx
spec:
podSelector:
matchLabels:
app: nginx
ingress:
matchLabels:
app: myapp
NAME POD-SELECTOR AGE
access-nginx app=nginx 6m
Contiv system after k8s policy:netctl group ls
Tenant Group Network IP Pool CfgdTag Policies Network profile
default default default-net
default default-group default-net ingress-policy,access-nginx
3. Bringup Ingress policy Pod and Src Pods
:
kubectl create -f nginx-deployment.yaml:
kubectl create -f apod.yamlkubectl get pods -o wideNAME READY STATUS RESTARTS AGE IP NODE
apod 1/1 Running 0 2m 10.233.64.8 k8s1
nginx-deployment-431080787-6b6zh 1/1 Running 0 2m 10.233.64.7 k8s1
nginx-deployment-431080787-9d949 1/1 Running 0 2m 10.233.64.6 k8s1
netctl policy rule-ls access-nginx
Incoming Rules:
Rule Priority From EndpointGroup From Network From IpAddress TO IpAddress Protocol Port Action
access-nginx-10.233.64.6-10.233.64.8 2 10.233.64.8 10.233.64.6 0 allow
access-nginx-10.233.64.7-10.233.64.8 2 10.233.64.8 10.233.64.7 0 allow
Outgoing Rules:
Rule Priority To EndpointGroup To Network To IpAddress Protocol Port Action
====
-Result : Make sure update policy rules programmed in contiv system