diff --git a/build/charts/antrea/crds/packetcapture.yaml b/build/charts/antrea/crds/packetcapture.yaml index b9a1d9ed9df..fec130517ed 100644 --- a/build/charts/antrea/crds/packetcapture.yaml +++ b/build/charts/antrea/crds/packetcapture.yaml @@ -160,7 +160,7 @@ spec: properties: url: type: string - pattern: 's{0,1}ftps{0,1}:\/\/[\w-_./]+:\d+' + pattern: 'sftps{0,1}:\/\/[\w-_./]+:\d+' status: type: object properties: diff --git a/build/yamls/antrea-aks.yml b/build/yamls/antrea-aks.yml index f0033db8359..082fa50066d 100644 --- a/build/yamls/antrea-aks.yml +++ b/build/yamls/antrea-aks.yml @@ -3060,7 +3060,7 @@ spec: properties: url: type: string - pattern: 's{0,1}ftps{0,1}:\/\/[\w-_./]+:\d+' + pattern: 'sftps{0,1}:\/\/[\w-_./]+:\d+' status: type: object properties: diff --git a/build/yamls/antrea-crds.yml b/build/yamls/antrea-crds.yml index 57a4ca00448..6dd3719121a 100644 --- a/build/yamls/antrea-crds.yml +++ b/build/yamls/antrea-crds.yml @@ -3033,7 +3033,7 @@ spec: properties: url: type: string - pattern: 's{0,1}ftps{0,1}:\/\/[\w-_./]+:\d+' + pattern: 'sftps{0,1}:\/\/[\w-_./]+:\d+' status: type: object properties: diff --git a/build/yamls/antrea-eks.yml b/build/yamls/antrea-eks.yml index ebdb0d706e6..2403b02cba3 100644 --- a/build/yamls/antrea-eks.yml +++ b/build/yamls/antrea-eks.yml @@ -3060,7 +3060,7 @@ spec: properties: url: type: string - pattern: 's{0,1}ftps{0,1}:\/\/[\w-_./]+:\d+' + pattern: 'sftps{0,1}:\/\/[\w-_./]+:\d+' status: type: object properties: diff --git a/build/yamls/antrea-gke.yml b/build/yamls/antrea-gke.yml index 272241253a2..b7e77155fed 100644 --- a/build/yamls/antrea-gke.yml +++ b/build/yamls/antrea-gke.yml @@ -3060,7 +3060,7 @@ spec: properties: url: type: string - pattern: 's{0,1}ftps{0,1}:\/\/[\w-_./]+:\d+' + pattern: 'sftps{0,1}:\/\/[\w-_./]+:\d+' status: type: object properties: diff --git a/build/yamls/antrea-ipsec.yml b/build/yamls/antrea-ipsec.yml index 6002162a9e4..34ea345f0d4 100644 --- a/build/yamls/antrea-ipsec.yml +++ b/build/yamls/antrea-ipsec.yml @@ -3060,7 +3060,7 @@ spec: properties: url: type: string - pattern: 's{0,1}ftps{0,1}:\/\/[\w-_./]+:\d+' + pattern: 'sftps{0,1}:\/\/[\w-_./]+:\d+' status: type: object properties: diff --git a/build/yamls/antrea.yml b/build/yamls/antrea.yml index 0b5b3ec1bfa..30f54afb0f1 100644 --- a/build/yamls/antrea.yml +++ b/build/yamls/antrea.yml @@ -3060,7 +3060,7 @@ spec: properties: url: type: string - pattern: 's{0,1}ftps{0,1}:\/\/[\w-_./]+:\d+' + pattern: 'sftps{0,1}:\/\/[\w-_./]+:\d+' status: type: object properties: diff --git a/docs/packetcapture-guide.md b/docs/packetcapture-guide.md index 75936eca722..044f791ff1e 100644 --- a/docs/packetcapture-guide.md +++ b/docs/packetcapture-guide.md @@ -72,7 +72,7 @@ spec: name: backend packet: ipFamily: IPv4 - protocol: TCP # support arbitrary number values and string values in [TCP,UDP,ICMP] + protocol: TCP # support arbitrary number values and string values in [TCP,UDP,ICMP] (case insensitive) transportHeader: tcp: dstPort: 8080 # Destination port needs to be set when the protocol is TCP/UDP. diff --git a/pkg/agent/packetcapture/packetcapture_controller.go b/pkg/agent/packetcapture/packetcapture_controller.go index 31c40f3c45c..3f81d06881d 100644 --- a/pkg/agent/packetcapture/packetcapture_controller.go +++ b/pkg/agent/packetcapture/packetcapture_controller.go @@ -22,6 +22,7 @@ import ( "os" "path/filepath" "slices" + "strings" "sync" "time" @@ -75,8 +76,7 @@ const ( // marked as Pending until they can be processed. maxConcurrentCaptures = 16 - // reason for timeout - captureTimeoutReason = "PacketCapture timeout" + contextTimeoutErrMsg = "context deadline exceeded" defaultTimeoutDuration = 60 * time.Second captureStatusUpdatePeriod = 10 * time.Second @@ -336,8 +336,8 @@ func (c *Controller) validatePacketCapture(spec *crdv1alpha1.PacketCaptureSpec) protocol := spec.Packet.Protocol if protocol != nil { if protocol.Type == intstr.String { - if _, ok := capture.ProtocolMap[protocol.StrVal]; !ok { - return fmt.Errorf("invalid protocol string, supported values are: %v", slices.Collect(maps.Keys(capture.ProtocolMap))) + if _, ok := capture.ProtocolMap[strings.ToUpper(protocol.StrVal)]; !ok { + return fmt.Errorf("invalid protocol string, supported values are: %v (case insensitive)", slices.Collect(maps.Keys(capture.ProtocolMap))) } } } @@ -396,11 +396,13 @@ func (c *Controller) getTargetCaptureDevice(pc *crdv1alpha1.PacketCapture) *stri return &podInterfaces[0].InterfaceName } +// startPacketCapture starts the capture on the target device. The actual capture process will be started +// in a separated go routine. func (c *Controller) startPacketCapture(ctx context.Context, pc *crdv1alpha1.PacketCapture, device *string) error { klog.V(4).InfoS("Started processing PacketCapture", "name", pc.Name) pcState := c.captures[pc.Name] pcState.name = pc.Name - srcIP, dstIp, err := c.parseIPs(pc) + srcIP, dstIp, err := c.parseIPs(ctx, pc) if err != nil { return err } @@ -440,7 +442,7 @@ func (c *Controller) performCapture( klog.ErrorS(err, "Failed to start capture") return err } - + klog.InfoS("Start capture packets", "name", pc.Name, "device", device) for { select { case packet := <-packets: @@ -476,7 +478,7 @@ func (c *Controller) performCapture( return err } if pc.Spec.FileServer != nil { - err = c.uploadPackets(pc, captureState.pcapngFile) + err = c.uploadPackets(ctx, pc, captureState.pcapngFile) klog.V(4).InfoS("Upload captured packets", "name", pc.Name, "path", path) statusPath = fmt.Sprintf("%s/%s.pcapng", pc.Spec.FileServer.URL, pc.Name) } @@ -491,7 +493,7 @@ func (c *Controller) performCapture( } } // report capture status. - c.addPacketCapture(pc) + c.enqueuePacketCapture(pc) } case <-ctx.Done(): return ctx.Err() @@ -499,7 +501,7 @@ func (c *Controller) performCapture( } } -func (c *Controller) getPodIP(podRef *crdv1alpha1.PodReference) (net.IP, error) { +func (c *Controller) getPodIP(ctx context.Context, podRef *crdv1alpha1.PodReference) (net.IP, error) { podInterfaces := c.interfaceStore.GetContainerInterfacesByPod(podRef.Name, podRef.Namespace) var podIP net.IP if len(podInterfaces) > 0 { @@ -521,9 +523,9 @@ func (c *Controller) getPodIP(podRef *crdv1alpha1.PodReference) (net.IP, error) return podIP, nil } -func (c *Controller) parseIPs(pc *crdv1alpha1.PacketCapture) (srcIP, dstIP net.IP, err error) { +func (c *Controller) parseIPs(ctx context.Context, pc *crdv1alpha1.PacketCapture) (srcIP, dstIP net.IP, err error) { if pc.Spec.Source.Pod != nil { - srcIP, err = c.getPodIP(pc.Spec.Source.Pod) + srcIP, err = c.getPodIP(ctx, pc.Spec.Source.Pod) } else if pc.Spec.Source.IP != nil { srcIP = net.ParseIP(*pc.Spec.Source.IP) if srcIP == nil { @@ -532,7 +534,7 @@ func (c *Controller) parseIPs(pc *crdv1alpha1.PacketCapture) (srcIP, dstIP net.I } if pc.Spec.Destination.Pod != nil { - dstIP, err = c.getPodIP(pc.Spec.Destination.Pod) + dstIP, err = c.getPodIP(ctx, pc.Spec.Destination.Pod) } else if pc.Spec.Destination.IP != nil { dstIP = net.ParseIP(*pc.Spec.Destination.IP) if dstIP == nil { @@ -553,7 +555,7 @@ func (c *Controller) generatePacketsPathForServer(name string) string { return name + ".pcapng" } -func (c *Controller) uploadPackets(pc *crdv1alpha1.PacketCapture, outputFile afero.File) error { +func (c *Controller) uploadPackets(ctx context.Context, pc *crdv1alpha1.PacketCapture, outputFile afero.File) error { klog.V(2).InfoS("Uploading captured packets for PacketCapture", "name", pc.Name) uploader, err := c.getUploaderByProtocol(sftpProtocol) if err != nil { @@ -566,7 +568,7 @@ func (c *Controller) uploadPackets(pc *crdv1alpha1.PacketCapture, outputFile afe Name: fileServerAuthSecretName, Namespace: env.GetAntreaNamespace(), } - serverAuth, err := auth.GetAuthConfigurationFromSecret(context.TODO(), auth.BasicAuthenticationType, &authSecret, c.kubeClient) + serverAuth, err := auth.GetAuthConfigurationFromSecret(ctx, auth.BasicAuthenticationType, &authSecret, c.kubeClient) if err != nil { klog.ErrorS(err, "Failed to get authentication for the file server", "name", pc.Name, "authSecret", authSecret) return err @@ -606,14 +608,14 @@ func (c *Controller) updateStatus(name string, state *packetCaptureState) error Reason: "CaptureFailed", Message: state.err.Error(), }) - if state.err.Error() == captureTimeoutReason { + if state.err.Error() == contextTimeoutErrMsg { conditions = []crdv1alpha1.PacketCaptureCondition{ { Type: crdv1alpha1.PacketCaptureCompleted, Status: metav1.ConditionStatus(v1.ConditionTrue), LastTransitionTime: t, Reason: "Timeout", - Message: captureTimeoutReason, + Message: contextTimeoutErrMsg, }, } } else if state.isCaptureSuccessful() { diff --git a/pkg/agent/packetcapture/packetcapture_controller_test.go b/pkg/agent/packetcapture/packetcapture_controller_test.go index 411d7f78708..101d471a95d 100644 --- a/pkg/agent/packetcapture/packetcapture_controller_test.go +++ b/pkg/agent/packetcapture/packetcapture_controller_test.go @@ -99,10 +99,6 @@ var ( func generateTestSecret() *v1.Secret { return &v1.Secret{ - TypeMeta: metav1.TypeMeta{ - Kind: "Secret", - APIVersion: "v1", - }, ObjectMeta: metav1.ObjectMeta{ Name: "AAA", Namespace: "default", @@ -205,16 +201,7 @@ type fakePacketCaptureController struct { func newFakePacketCaptureController(t *testing.T, runtimeObjects []runtime.Object, initObjects []runtime.Object) *fakePacketCaptureController { controller := gomock.NewController(t) - objs := []runtime.Object{ - &pod1, - &pod2, - &pod3, - &secret1, - } - objs = append(objs, generateTestSecret()) - if runtimeObjects != nil { - objs = append(objs, runtimeObjects...) - } + objs := append(runtimeObjects, &pod1, &pod2, &pod3, &secret1, generateTestSecret()) kubeClient := fake.NewSimpleClientset(objs...) crdClient := fakeversioned.NewSimpleClientset(initObjects...) crdInformerFactory := crdinformers.NewSharedInformerFactory(crdClient, 0) @@ -405,7 +392,7 @@ func TestPacketCaptureControllerRun(t *testing.T) { } // delete cr - err := pcc.crdClient.CrdV1alpha1().PacketCaptures().Delete(context.TODO(), item.pc.Name, metav1.DeleteOptions{}) + err = pcc.crdClient.CrdV1alpha1().PacketCaptures().Delete(context.TODO(), item.pc.Name, metav1.DeleteOptions{}) require.NoError(t, err) stopCh <- struct{}{}