Skip to content
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

[Windows] CNI Server installs OpenFlow entries by PortStatus #6763

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

wenyingd
Copy link
Contributor

@wenyingd wenyingd commented Oct 23, 2024

This change has introduced podIfaceMonitor in CNI Server module, which listens for the OpenFlow PortStatus message when a new OpenFlow port is allocated in OVS. After receiving the message, antrea-agent Windows will install Pod related OpenFlow entries. If the OpenFlow port is not allocated within 30s after the CmdAdd request is responded, an annotation is added on the Pod with key "pod.antrea.io/not-ready". The annotation is removed if the Pod network is ready.

Fix: #6721

createTime time.Time
}

type podIfaceMonitor struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

when I look at all this new code, it seems that there is nothing platform-specific about it: it could build and run on Linux just as well as on Windows (unless I am missing something). Given this, could we move the podInfaceMonitor code to a separate file or sub-package, that will not be platform-specific. It will make it much easier to update that code and unit test it locally on macOS laptops or Linux dev servers. I think this code deserved to be unit-tested independently of the rest of the pod configuration code.

On Windows, we can use a pointer to an actual instance of podIfaceMonitor, and on Linux, we can use a nil pointer.

}
}

func (m *podIfaceMonitor) monitorUnReadyInterface(stopCh <-chan struct{}) {
Copy link
Contributor

Choose a reason for hiding this comment

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

typically by convention we name a function like this Run, and we call Run in its own goroutine

func (m *podIfaceMonitor) updatePodFlows(ifName string, ofPort int32) error {
ifConfig, found := m.ifaceStore.GetInterfaceByName(ifName)
if !found {
klog.Info("Interface config is not found", "name", ifName)
Copy link
Contributor

Choose a reason for hiding this comment

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

you probably meant to use klog.InfoS here. Please check other occurrences as well.

m.ifaceStore.UpdateInterface(ifConfig)

// Install OpenFlow entries for the Pod.
klog.V(2).Infof("Setting up Openflow entries for container %s", containerID)
Copy link
Contributor

Choose a reason for hiding this comment

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

Please make sure you use structured logging (klog.InfoS / klog.ErrorS) in all new code

return nil
}

func (m *podIfaceMonitor) updatePodUnreadyAnnotation(podNamespace, podName string, addAnnotation bool) {
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 this function would benefit from having an actual context.Context as a parameter

It's true that when we started the Antrea codebase, contexts were not as much of a thing, so we have a lot of "placeholders" (context.TODO() or context.Background()). For this new function, we should add ctx context.Context, and the caller can choose what to do.

"annotations": map[string]interface{}{types.PodNotReadyAnnotationKey: ""},
},
})
m.kubeClient.CoreV1().Pods(podNamespace).Patch(context.Background(), podName, apitypes.MergePatchType, patch, metav1.PatchOptions{})
Copy link
Contributor

Choose a reason for hiding this comment

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

should we check the error?

}

func (m *podIfaceMonitor) updatePodUnreadyAnnotation(podNamespace, podName string, addAnnotation bool) {
pod, err := m.kubeClient.CoreV1().Pods(podNamespace).Get(context.Background(), podName, metav1.GetOptions{})
Copy link
Contributor

Choose a reason for hiding this comment

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

usually we avoid reading directly from the K8s API. Is using an informer possible here?

podInfo := value.(*unReadyPodInfo)
if !podInfo.annotated && time.Now().Sub(podInfo.createTime).Seconds() > podNotReadyTimeInSeconds {
m.updatePodUnreadyAnnotation(podInfo.podNamespace, podInfo.podName, true)
podInfo.annotated = true
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 this should be conditional: patching the Pod can fail and we want to be able to try again at the next tick.

}

func (m *podIfaceMonitor) updateUnReadyPod(status *openflow15.PortStatus) {
ovsPort := string(bytes.Trim(status.Desc.Name, "\x00"))
Copy link
Contributor

Choose a reason for hiding this comment

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

It feels like this should be handled in libOpenflow?

Comment on lines +230 to +233
if err != nil {
klog.ErrorS(err, "Failed to get Pod when trying to update 'unready' annotations", "Namespace", podNamespace, "Name", podName)
return
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible for a Pod to no longer exist and still be in the map (because of some failure)? In this case we would never delete it from the map.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants