diff options
-rw-r--r-- | cmd/ovn4nfvk8s-cni/app/helper_linux.go | 23 | ||||
-rw-r--r-- | cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni.go | 5 | ||||
-rw-r--r-- | cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni_test.go | 126 | ||||
-rw-r--r-- | deploy/ovn4nfv-k8s-plugin-daemonset.yml | 571 | ||||
-rw-r--r-- | go.sum | 2 | ||||
-rw-r--r-- | internal/pkg/ovn/common.go | 53 | ||||
-rw-r--r-- | internal/pkg/ovn/ovn.go | 146 | ||||
-rw-r--r-- | internal/pkg/ovn/ovn_test.go | 180 | ||||
-rw-r--r-- | internal/pkg/ovn/utils.go | 8 | ||||
-rw-r--r-- | pkg/controller/pod/pod_controller.go | 31 |
10 files changed, 740 insertions, 405 deletions
diff --git a/cmd/ovn4nfvk8s-cni/app/helper_linux.go b/cmd/ovn4nfvk8s-cni/app/helper_linux.go index 676901e..2dba628 100644 --- a/cmd/ovn4nfvk8s-cni/app/helper_linux.go +++ b/cmd/ovn4nfvk8s-cni/app/helper_linux.go @@ -6,7 +6,7 @@ import ( "fmt" "net" "os/exec" - "regexp" + "strconv" "strings" "github.com/sirupsen/logrus" @@ -37,7 +37,7 @@ func renameLink(curName, newName string) error { return nil } -func setupInterface(netns ns.NetNS, containerID, ifName, macAddress, ipAddress, gatewayIP, defaultGateway string, mtu int) (*current.Interface, *current.Interface, error) { +func setupInterface(netns ns.NetNS, containerID, ifName, macAddress, ipAddress, gatewayIP, defaultGateway string, idx, mtu int) (*current.Interface, *current.Interface, error) { hostIface := ¤t.Interface{} contIface := ¤t.Interface{} @@ -97,9 +97,7 @@ func setupInterface(netns ns.NetNS, containerID, ifName, macAddress, ipAddress, } // rename the host end of veth pair - re := regexp.MustCompile("(\\d+)\\D*\\z") - index := re.FindAllString(ifName, -1) - hostIface.Name = containerID[:14] + index[0] + hostIface.Name = containerID[:14] + strconv.Itoa(idx) if err := renameLink(oldHostVethName, hostIface.Name); err != nil { return nil, nil, fmt.Errorf("failed to rename %s to %s: %v", oldHostVethName, hostIface.Name, err) } @@ -108,21 +106,24 @@ func setupInterface(netns ns.NetNS, containerID, ifName, macAddress, ipAddress, } // ConfigureInterface sets up the container interface -var ConfigureInterface = func(args *skel.CmdArgs, namespace, podName, macAddress, ipAddress, gatewayIP, interfaceName, defaultGateway string, mtu int) ([]*current.Interface, error) { +var ConfigureInterface = func(args *skel.CmdArgs, namespace, podName, macAddress, ipAddress, gatewayIP, interfaceName, defaultGateway string, idx, mtu int) ([]*current.Interface, error) { netns, err := ns.GetNS(args.Netns) if err != nil { return nil, fmt.Errorf("failed to open netns %q: %v", args.Netns, err) } defer netns.Close() - hostIface, contIface, err := setupInterface(netns, args.ContainerID, interfaceName, macAddress, ipAddress, gatewayIP, defaultGateway, mtu) - if err != nil { - return nil, err - } + var ifaceID string - if interfaceName != "" { + if interfaceName != "*" { ifaceID = fmt.Sprintf("%s_%s_%s", namespace, podName, interfaceName) } else { ifaceID = fmt.Sprintf("%s_%s", namespace, podName) + interfaceName = args.IfName + defaultGateway = "true" + } + hostIface, contIface, err := setupInterface(netns, args.ContainerID, interfaceName, macAddress, ipAddress, gatewayIP, defaultGateway, idx, mtu) + if err != nil { + return nil, err } ovsArgs := []string{ diff --git a/cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni.go b/cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni.go index 2585fcf..c176700 100644 --- a/cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni.go +++ b/cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni.go @@ -142,8 +142,7 @@ func addMultipleInterfaces(args *skel.CmdArgs, ovnAnnotation, namespace, podName logrus.Errorf("addMultipleInterfaces: interface can't be null") return nil } - logrus.Debugf("addMultipleInterfaces: ipAddress %v %v", ipAddress, interfaceName) - interfacesArray, err = app.ConfigureInterface(args, namespace, podName, macAddress, ipAddress, gatewayIP, interfaceName, defaultGateway, config.Default.MTU) + interfacesArray, err = app.ConfigureInterface(args, namespace, podName, macAddress, ipAddress, gatewayIP, interfaceName, defaultGateway, index, config.Default.MTU) if err != nil { logrus.Errorf("Failed to configure interface in pod: %v", err) return nil @@ -318,7 +317,7 @@ func cmdDel(args *skel.CmdArgs) error { } func main() { - logrus.Infof("ovn4nfvk8s-cni CNI Invoked by Multus") + logrus.Infof("ovn4nfvk8s-cni invoked") c := cli.NewApp() c.Name = "ovn4nfvk8s-cni" c.Usage = "a CNI plugin to set up or tear down a additional interfaces with OVN" diff --git a/cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni_test.go b/cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni_test.go deleted file mode 100644 index 16296e3..0000000 --- a/cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni_test.go +++ /dev/null @@ -1,126 +0,0 @@ -// +build linux - -package main - -import ( - "encoding/json" - - "github.com/containernetworking/cni/pkg/skel" - "github.com/containernetworking/cni/pkg/types" - "github.com/containernetworking/cni/pkg/types/current" - "net" - "ovn4nfv-k8s-plugin/cmd/ovn4nfvk8s-cni/app" - "reflect" - "testing" -) - -func TestAddMultipleInterfaces(t *testing.T) { - oldConfigureInterface := app.ConfigureInterface - // as we are exiting, revert ConfigureInterface back at end of function - defer func() { app.ConfigureInterface = oldConfigureInterface }() - app.ConfigureInterface = func(args *skel.CmdArgs, namespace, podName, macAddress, ipAddress, gatewayIP, interfaceName, defaultGateway string, mtu int) ([]*current.Interface, error) { - return []*current.Interface{ - { - Name: "pod", - Mac: "0a:00:00:00:00:0c", - Sandbox: "102103104", - }}, nil - } - oldConfigureRoute := app.ConfigureRoute - defer func() { app.ConfigureRoute = oldConfigureRoute }() - app.ConfigureRoute = func(args *skel.CmdArgs, dst, gw, dev string) error { - return nil - } - - args := &skel.CmdArgs{"102103104", "default", "eth0", "", "", nil} - ovnAnnotation := "[{\"ip_address\":\"172.16.24.2/24\", \"mac_address\":\"0a:00:00:00:00:0c\", \"gateway_ip\": \"172.16.24.1\",\"interface\":\"net0\"}] " - result := addMultipleInterfaces(args, ovnAnnotation, "default", "pod") - if result == nil { - t.Errorf("Failed addMultipleInterfaces %+v", ovnAnnotation) - } - resultSave := result - ovnAnnotation = "[{\"ip_address\":\"172.16.24.2/24\", \"mac_address\":\"0a:00:00:00:00:0c\", \"gateway_ip\": \"172.16.24.1\",\"defaultGateway\":\"true\",\"interface\":\"net0\"}] " - result = addMultipleInterfaces(args, ovnAnnotation, "default", "pod") - if result == nil { - t.Errorf("Failed addMultipleInterfaces %+v", ovnAnnotation) - } - ovnAnnotation = "[{\"ip_address\":\"172.16.24.2/24\", \"mac_address\":\"0a:00:00:00:00:0c\", \"gateway_ip\": \"172.16.24.1\"}] " - result = addMultipleInterfaces(args, ovnAnnotation, "default", "pod") - if result != nil { - t.Errorf("Failed addMultipleInterfaces %+v", ovnAnnotation) - } - ovnAnnotation = "[{\"mac_address\":\"0a:00:00:00:00:0c\", \"gateway_ip\": \"172.16.24.1\",\"interface\":\"net0\"}] " - result = addMultipleInterfaces(args, ovnAnnotation, "default", "pod") - if result != nil { - t.Errorf("Failed addMultipleInterfaces %+v", ovnAnnotation) - } - ovnAnnotation = "[{\"ip_address\":\"172.16.24.2/24\", \"mac_address\":\"0a:00:00:00:00:0c\", \"gateway_ip\": \"172.16.24.1\",\"interface\":\"net0\"}, {\"ip_address\":\"172.16.25.2/24\", \"mac_address\":\"0a:00:00:00:00:0d\", \"gateway_ip\": \"172.16.25.1\",\"interface\":\"net1\"}]" - result = addMultipleInterfaces(args, ovnAnnotation, "default", "pod") - if result == nil { - t.Errorf("Failed addMultipleInterfaces %+v", ovnAnnotation) - } - ovnAnnotation = "[{\"ip_address\":\"172.16.24.2/24\", \"mac_address\":\"0a:00:00:00:00:0c\", \"gateway_ip\": \"172.16.24.1\",\"interface\":\"net0\", \"defaultGateway\":\"true\"}, {\"ip_address\":\"172.16.25.2/24\", \"mac_address\":\"0a:00:00:00:00:0d\", \"gateway_ip\": \"172.16.25.1\",\"interface\":\"net1\"}]" - result = addMultipleInterfaces(args, ovnAnnotation, "default", "pod") - if result == nil { - t.Errorf("Failed addMultipleInterfaces %+v", ovnAnnotation) - } - // Test add route feature - ovnRoutesAnnotation := "[{ \"dst\": \"172.16.29.0/24\", \"gw\": \"172.16.24.1\", \"dev\": \"eth0\" }]" - result = addRoutes(args, ovnRoutesAnnotation, resultSave) - if result == nil { - t.Errorf("Failed addRoutes %+v", ovnRoutesAnnotation) - } - - ovnRoutesAnnotation = "[{ \"dst\": \"172.16.30.0/24\", \"gw\": \"172.16.25.1\", \"dev\": \"eth0\"}, { \"dst\": \"172.16.31.0/24\", \"gw\": \"172.16.26.1\", \"dev\": \"eth1\" }]" - result = addRoutes(args, ovnRoutesAnnotation, resultSave) - if result == nil { - t.Errorf("Failed addRoutes %+v", ovnRoutesAnnotation) - } - newResult, err := current.NewResultFromResult(result) - if err != nil { - t.Errorf("Failed addMultipleInterfaces %+v", newResult) - } - addr1, addrNet1, _ := net.ParseCIDR("172.16.24.2/24") - addr2, addrNet2, _ := net.ParseCIDR("172.16.29.0/24") - addr3, addrNet3, _ := net.ParseCIDR("172.16.30.0/24") - addr4, addrNet4, _ := net.ParseCIDR("172.16.31.0/24") - expectedResult := ¤t.Result{ - CNIVersion: "0.3.1", - Interfaces: []*current.Interface{ - { - Name: "pod", - Mac: "0a:00:00:00:00:0c", - Sandbox: "102103104", - }, - }, - IPs: []*current.IPConfig{ - { - Version: "4", - Interface: current.Int(1), - Address: net.IPNet{IP: addr1, Mask: addrNet1.Mask}, - Gateway: net.ParseIP("172.16.24.1"), - }, - }, - Routes: []*types.Route{ - { - Dst: net.IPNet{IP: addr2, Mask: addrNet2.Mask}, - GW: net.ParseIP("172.16.24.1"), - }, - { - Dst: net.IPNet{IP: addr3, Mask: addrNet3.Mask}, - GW: net.ParseIP("172.16.25.1"), - }, - { - Dst: net.IPNet{IP: addr4, Mask: addrNet4.Mask}, - GW: net.ParseIP("172.16.26.1"), - }, - }, - DNS: types.DNS{}, - } - jsonBytes1, err := json.Marshal(newResult.Routes) - jsonBytes2, err := json.Marshal(expectedResult.Routes) - if !reflect.DeepEqual(jsonBytes1, jsonBytes2) { - t.Errorf("Routes are not correct") - } - -} diff --git a/deploy/ovn4nfv-k8s-plugin-daemonset.yml b/deploy/ovn4nfv-k8s-plugin-daemonset.yml new file mode 100644 index 0000000..13e749f --- /dev/null +++ b/deploy/ovn4nfv-k8s-plugin-daemonset.yml @@ -0,0 +1,571 @@ + +--- + +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: networks.k8s.plugin.opnfv.org +spec: + group: k8s.plugin.opnfv.org + names: + kind: Network + listKind: NetworkList + plural: networks + singular: network + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + properties: + cniType: + description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + Important: Run "operator-sdk generate k8s" to regenerate code after + modifying this file Add custom validation using kubebuilder tags: + https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html' + type: string + dns: + properties: + domain: + type: string + nameservers: + items: + type: string + type: array + options: + items: + type: string + type: array + search: + items: + type: string + type: array + type: object + ipv4Subnets: + items: + properties: + excludeIps: + type: string + gateway: + type: string + name: + type: string + subnet: + type: string + required: + - name + - subnet + type: object + type: array + ipv6Subnets: + items: + properties: + excludeIps: + type: string + gateway: + type: string + name: + type: string + subnet: + type: string + required: + - name + - subnet + type: object + type: array + routes: + items: + properties: + dst: + type: string + gw: + type: string + required: + - dst + type: object + type: array + required: + - cniType + - ipv4Subnets + type: object + status: + properties: + state: + description: 'INSERT ADDITIONAL STATUS FIELD - define observed state + of cluster Important: Run "operator-sdk generate k8s" to regenerate + code after modifying this file Add custom validation using kubebuilder + tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html' + type: string + required: + - state + type: object + version: v1alpha1 + versions: + - name: v1alpha1 + served: true + storage: true + + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: providernetworks.k8s.plugin.opnfv.org +spec: + group: k8s.plugin.opnfv.org + names: + kind: ProviderNetwork + listKind: ProviderNetworkList + plural: providernetworks + singular: providernetwork + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + description: ProviderNetwork is the Schema for the providernetworks API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ProviderNetworkSpec defines the desired state of ProviderNetwork + properties: + cniType: + description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + Important: Run "operator-sdk generate k8s" to regenerate code after + modifying this file Add custom validation using kubebuilder tags: + https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html' + type: string + direct: + properties: + directNodeSelector: + type: string + nodeLabelList: + items: + type: string + type: array + providerInterfaceName: + type: string + required: + - directNodeSelector + - providerInterfaceName + type: object + dns: + properties: + domain: + type: string + nameservers: + items: + type: string + type: array + options: + items: + type: string + type: array + search: + items: + type: string + type: array + type: object + ipv4Subnets: + items: + properties: + excludeIps: + type: string + gateway: + type: string + name: + type: string + subnet: + type: string + required: + - name + - subnet + type: object + type: array + ipv6Subnets: + items: + properties: + excludeIps: + type: string + gateway: + type: string + name: + type: string + subnet: + type: string + required: + - name + - subnet + type: object + type: array + providerNetType: + type: string + routes: + items: + properties: + dst: + type: string + gw: + type: string + required: + - dst + type: object + type: array + vlan: + properties: + logicalInterfaceName: + type: string + nodeLabelList: + items: + type: string + type: array + providerInterfaceName: + type: string + vlanId: + type: string + vlanNodeSelector: + type: string + required: + - providerInterfaceName + - vlanId + - vlanNodeSelector + type: object + required: + - cniType + - ipv4Subnets + - providerNetType + type: object + status: + description: ProviderNetworkStatus defines the observed state of ProviderNetwork + properties: + state: + description: 'INSERT ADDITIONAL STATUS FIELD - define observed state + of cluster Important: Run "operator-sdk generate k8s" to regenerate + code after modifying this file Add custom validation using kubebuilder + tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html' + type: string + required: + - state + type: object + type: object + version: v1alpha1 + versions: + - name: v1alpha1 + served: true + storage: true +--- + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: k8s-nfn-sa + namespace: operator + +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + name: k8s-nfn-cr +rules: +- apiGroups: + - "" + resources: + - pods + - services + - endpoints + - persistentvolumeclaims + - events + - configmaps + - secrets + - nodes + verbs: + - '*' +- apiGroups: + - apps + resources: + - deployments + - daemonsets + - replicasets + - statefulsets + verbs: + - '*' +- apiGroups: + - monitoring.coreos.com + resources: + - servicemonitors + verbs: + - get + - create +- apiGroups: + - apps + resourceNames: + - nfn-operator + resources: + - deployments/finalizers + verbs: + - update +- apiGroups: + - k8s.plugin.opnfv.org + resources: + - '*' + - providernetworks + verbs: + - '*' + +--- + +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: k8s-nfn-crb +subjects: +- kind: Group + name: system:serviceaccounts + apiGroup: rbac.authorization.k8s.io +roleRef: + kind: ClusterRole + name: k8s-nfn-cr + apiGroup: rbac.authorization.k8s.io + + +--- + +apiVersion: v1 +kind: Service +metadata: + name: nfn-operator + namespace: operator +spec: + type: NodePort + ports: + - port: 50000 + protocol: TCP + targetPort: 50000 + selector: + name: nfn-operator + + +--- + +apiVersion: v1 +kind: ConfigMap +metadata: + name: ovn-controller-network + namespace: operator +data: + OVN_SUBNET: "10.244.64.0/18" + OVN_GATEWAYIP: "10.244.64.20/18" + OVN_EXCLUDEIPS: "10.244.64.0..10.244.64.16" + + +--- + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nfn-operator + namespace: operator +spec: + replicas: 1 + selector: + matchLabels: + name: nfn-operator + template: + metadata: + labels: + name: nfn-operator + spec: + hostNetwork: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: nfnType + operator: In + values: + - operator + tolerations: + - key: "node-role.kubernetes.io/master" + effect: "NoSchedule" + operator: "Exists" + serviceAccountName: k8s-nfn-sa + containers: + - name: nfn-operator + image: integratedcloudnative/ovn4nfv-k8s-plugin:master + command: ["/usr/local/bin/entrypoint", "operator"] + imagePullPolicy: IfNotPresent + envFrom: + - configMapRef: + name: ovn-controller-network + ports: + - containerPort: 50000 + protocol: TCP + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: OPERATOR_NAME + value: "nfn-operator" + +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: ovn4nfv-cni-config + namespace: operator + labels: + app: ovn4nfv +data: + ovn4nfv_k8s.conf: | + [logging] + loglevel=5 + logfile=/var/log/openvswitch/ovn4k8s.log + + [cni] + conf-dir=/etc/cni/net.d + plugin=ovn4nfvk8s-cni + + [kubernetes] + kubeconfig=/etc/kubernetes/admin.conf + +--- +apiVersion: extensions/v1beta1 +kind: DaemonSet +metadata: + name: ovn4nfv-cni + namespace: operator + labels: + app: ovn4nfv +spec: + updateStrategy: + type: RollingUpdate + template: + metadata: + labels: + app: ovn4nfv + spec: + hostNetwork: true + nodeSelector: + beta.kubernetes.io/arch: amd64 + tolerations: + - operator: Exists + effect: NoSchedule + containers: + - name: ovn4nfv + image: integratedcloudnative/ovn4nfv-k8s-plugin:master + command: ["/usr/local/bin/entrypoint", "cni"] + resources: + requests: + cpu: "100m" + memory: "50Mi" + limits: + cpu: "100m" + memory: "50Mi" + securityContext: + privileged: true + volumeMounts: + - name: cnibin + mountPath: /host/opt/cni/bin + - name: cniconf + mountPath: /host/etc/openvswitch + - name: ovn4nfv-cfg + mountPath: /tmp/ovn4nfv-conf + volumes: + - name: cnibin + hostPath: + path: /opt/cni/bin + - name: cniconf + hostPath: + path: /etc/openvswitch + - name: ovn4nfv-cfg + configMap: + name: ovn4nfv-cni-config + items: + - key: ovn4nfv_k8s.conf + path: ovn4nfv_k8s.conf + +--- +apiVersion: extensions/v1beta1 +kind: DaemonSet +metadata: + name: nfn-agent + namespace: operator + labels: + app: nfn-agent +spec: + updateStrategy: + type: RollingUpdate + template: + metadata: + labels: + app: nfn-agent + spec: + hostNetwork: true + nodeSelector: + beta.kubernetes.io/arch: amd64 + tolerations: + - operator: Exists + effect: NoSchedule + containers: + - name: nfn-agent + image: integratedcloudnative/ovn4nfv-k8s-plugin:master + command: ["/usr/local/bin/entrypoint", "agent"] + resources: + requests: + cpu: "100m" + memory: "50Mi" + limits: + cpu: "100m" + memory: "50Mi" + env: + - name: NFN_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + securityContext: + privileged: true + volumeMounts: + - mountPath: /run/openvswitch + name: host-run-ovs + - mountPath: /var/run/openvswitch + name: host-var-run-ovs + volumes: + - name: host-run-ovs + hostPath: + path: /run/openvswitch + - name: host-var-run-ovs + hostPath: + path: /var/run/openvswitch @@ -786,7 +786,7 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.0.0 h1:OyHbl+7IOECpPKfVK42oFr6N7+Y2dR+Jsb/IiDV3hOo= +gomodules.xyz/jsonpatch/v2 v2.0.0 h1:lHNQverf0+Gm1TbSbVIDWVXOhZ2FpZopxRqpr2uIjs4= gomodules.xyz/jsonpatch/v2 v2.0.0/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= gomodules.xyz/jsonpatch/v2 v2.0.1 h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0= gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= diff --git a/internal/pkg/ovn/common.go b/internal/pkg/ovn/common.go index a294004..e38c440 100644 --- a/internal/pkg/ovn/common.go +++ b/internal/pkg/ovn/common.go @@ -246,6 +246,59 @@ func setupDistributedRouter(name string) error { return nil } +// CreateNetwork in OVN controller +func createOvnLS(name, subnet, gatewayIP, excludeIps string) (gatewayIPMask string, err error) { + var stdout, stderr string + + output, stderr, err := RunOVNNbctl("--data=bare", "--no-heading", + "--columns=name", "find", "logical_switch", "name="+name) + if err != nil { + log.Error(err, "Error in reading logical switch", "stderr", stderr) + return + } + + if strings.Compare(name, output) == 0 { + log.V(1).Info("Logical Switch already exists, delete first to update/recreate", "name", name) + return "", fmt.Errorf("LS exists") + } + + _, cidr, err := net.ParseCIDR(subnet) + if err != nil { + log.Error(err, "ovnNetwork '%s' invalid subnet CIDR", "name", name) + return + + } + firstIP := NextIP(cidr.IP) + n, _ := cidr.Mask.Size() + + var gwIP net.IP + if gatewayIP != "" { + gwIP, _, err = net.ParseCIDR(gatewayIP) + if err != nil { + // Check if this is a valid IP address + gwIP = net.ParseIP(gatewayIP) + } + } + // If no valid Gateway use the first IP address for GatewayIP + if gwIP == nil { + gatewayIPMask = fmt.Sprintf("%s/%d", firstIP.String(), n) + } else { + gatewayIPMask = fmt.Sprintf("%s/%d", gwIP.String(), n) + } + + // Create a logical switch and set its subnet. + if excludeIps != "" { + stdout, stderr, err = RunOVNNbctl("--wait=hv", "--", "--may-exist", "ls-add", name, "--", "set", "logical_switch", name, "other-config:subnet="+subnet, "external-ids:gateway_ip="+gatewayIPMask, "other-config:exclude_ips="+excludeIps) + } else { + stdout, stderr, err = RunOVNNbctl("--wait=hv", "--", "--may-exist", "ls-add", name, "--", "set", "logical_switch", name, "other-config:subnet="+subnet, "external-ids:gateway_ip="+gatewayIPMask) + } + if err != nil { + log.Error(err, "Failed to create a logical switch", "name", name, "stdout", stdout, "stderr", stderr) + return + } + return +} + // generateMac generates mac address. func generateMac() string { prefix := "00:00:00" diff --git a/internal/pkg/ovn/ovn.go b/internal/pkg/ovn/ovn.go index 6e9cd79..6f7951a 100644 --- a/internal/pkg/ovn/ovn.go +++ b/internal/pkg/ovn/ovn.go @@ -6,7 +6,7 @@ import ( kapi "k8s.io/api/core/v1" kexec "k8s.io/utils/exec" "math/rand" - "net" + "os" k8sv1alpha1 "ovn4nfv-k8s-plugin/pkg/apis/k8s/v1alpha1" "strings" "time" @@ -16,12 +16,43 @@ type Controller struct { gatewayCache map[string]string } +type OVNNetworkConf struct { + Subnet string + GatewayIP string + ExcludeIPs string +} + const ( ovn4nfvRouterName = "ovn4nfv-master" // Ovn4nfvAnnotationTag tag on already processed Pods Ovn4nfvAnnotationTag = "k8s.plugin.opnfv.org/ovnInterfaces" + // OVN Default Network name + Ovn4nfvDefaultNw = "ovn4nfvk8s-default-nw" ) +var ovnConf *OVNNetworkConf + +func GetOvnNetConf() error { + ovnConf = &OVNNetworkConf{} + + ovnConf.Subnet = os.Getenv("OVN_SUBNET") + if ovnConf.Subnet == "" { + fmt.Errorf("OVN subnet is not set in nfn-operator configmap env") + } + + ovnConf.GatewayIP = os.Getenv("OVN_GATEWAYIP") + if ovnConf.GatewayIP == "" { + fmt.Errorf("OVN gatewayIP is not set in nfn-operator configmap env") + } + + ovnConf.ExcludeIPs = os.Getenv("OVN_EXCLUDEIPS") + if ovnConf.ExcludeIPs == "" { + fmt.Errorf("OVN excludeIPs is not set in nfn-operator configmap env") + } + + return nil +} + type netInterface struct { Name string Interface string @@ -43,10 +74,16 @@ func NewOvnController(exec kexec.Interface) (*Controller, error) { log.Error(err, "Failed to initialize exec helper") return nil, err } + + if err := GetOvnNetConf(); err != nil { + log.Error(err, "nfn-operator OVN Network configmap is not set") + return nil, err + } if err := SetupOvnUtils(); err != nil { log.Error(err, "Failed to initialize OVN State") return nil, err } + ovnCtl = &Controller{ gatewayCache: make(map[string]string), } @@ -64,10 +101,6 @@ func GetOvnController() (*Controller, error) { // AddLogicalPorts adds ports to the Pod func (oc *Controller) AddLogicalPorts(pod *kapi.Pod, ovnNetObjs []map[string]interface{}) (key, value string) { - if ovnNetObjs == nil { - return - } - if pod.Spec.HostNetwork { return } @@ -78,28 +111,38 @@ func (oc *Controller) AddLogicalPorts(pod *kapi.Pod, ovnNetObjs []map[string]int } var ovnString, outStr string + var defaultInterface bool + ovnString = "[" var ns netInterface for _, net := range ovnNetObjs { - err := mapstructure.Decode(net, &ns) if err != nil { log.Error(err, "mapstruct error", "network", net) return } - if !oc.FindLogicalSwitch(ns.Name) { log.Info("Logical Switch not found") return } - if ns.Interface == "" { + if ns.Name == Ovn4nfvDefaultNw { + defaultInterface = true + } + if ns.Interface == "" && ns.Name != Ovn4nfvDefaultNw { log.Info("Interface name must be provided") return } if ns.DefaultGateway == "" { ns.DefaultGateway = "false" } - outStr = oc.addLogicalPortWithSwitch(pod, ns.Name, ns.IPAddress, ns.MacAddress, ns.Interface, ns.NetType) + var portName string + if ns.Interface != "" { + portName = fmt.Sprintf("%s_%s_%s", pod.Namespace, pod.Name, ns.Interface) + } else { + portName = fmt.Sprintf("%s_%s", pod.Namespace, pod.Name) + ns.Interface = "*" + } + outStr = oc.addLogicalPortWithSwitch(pod, ns.Name, ns.IPAddress, ns.MacAddress, portName) if outStr == "" { return } @@ -110,7 +153,21 @@ func (oc *Controller) AddLogicalPorts(pod *kapi.Pod, ovnNetObjs []map[string]int ovnString += tmpString ovnString += "," } - last := len(ovnString) - 1 + var last int + if defaultInterface == false { + // Add Default interface + portName := fmt.Sprintf("%s_%s", pod.Namespace, pod.Name) + outStr = oc.addLogicalPortWithSwitch(pod, Ovn4nfvDefaultNw, "", "", portName) + if outStr == "" { + return + } + last := len(outStr) - 1 + tmpString := outStr[:last] + tmpString += "," + "\\\"interface\\\":" + "\\\"" + "*" + "\\\"}" + ovnString += tmpString + ovnString += "," + } + last = len(ovnString) - 1 ovnString = ovnString[:last] ovnString += "]" key = Ovn4nfvAnnotationTag @@ -121,6 +178,7 @@ func (oc *Controller) AddLogicalPorts(pod *kapi.Pod, ovnNetObjs []map[string]int // DeleteLogicalPorts deletes the OVN ports for the pod func (oc *Controller) DeleteLogicalPorts(name, namespace string) { + log.Info("DeleteLogicalPorts") logicalPort := fmt.Sprintf("%s_%s", namespace, name) // get the list of logical ports from OVN @@ -134,7 +192,7 @@ func (oc *Controller) DeleteLogicalPorts(name, namespace string) { for _, existingPort := range existingLogicalPorts { if strings.Contains(existingPort, logicalPort) { // found, delete this logical port - log.V(1).Info("Deleting", "Port", existingPort) + log.Info("Deleting", "Port", existingPort) stdout, stderr, err := RunOVNNbctl("--if-exists", "lsp-del", existingPort) if err != nil { @@ -146,59 +204,6 @@ func (oc *Controller) DeleteLogicalPorts(name, namespace string) { } // CreateNetwork in OVN controller -func (oc *Controller) createOvnLS(name, subnet, gatewayIP, excludeIps string) (gatewayIPMask string, err error) { - var stdout, stderr string - - output, stderr, err := RunOVNNbctl("--data=bare", "--no-heading", - "--columns=name", "find", "logical_switch", "name="+name) - if err != nil { - log.Error(err, "Error in reading logical switch", "stderr", stderr) - return - } - - if strings.Compare(name, output) == 0 { - log.V(1).Info("Logical Switch already exists, delete first to update/recreate", "name", name) - return "", fmt.Errorf("LS exists") - } - - _, cidr, err := net.ParseCIDR(subnet) - if err != nil { - log.Error(err, "ovnNetwork '%s' invalid subnet CIDR", "name", name) - return - - } - firstIP := NextIP(cidr.IP) - n, _ := cidr.Mask.Size() - - var gwIP net.IP - if gatewayIP != "" { - gwIP, _, err = net.ParseCIDR(gatewayIP) - if err != nil { - // Check if this is a valid IP address - gwIP = net.ParseIP(gatewayIP) - } - } - // If no valid Gateway use the first IP address for GatewayIP - if gwIP == nil { - gatewayIPMask = fmt.Sprintf("%s/%d", firstIP.String(), n) - } else { - gatewayIPMask = fmt.Sprintf("%s/%d", gwIP.String(), n) - } - - // Create a logical switch and set its subnet. - if excludeIps != "" { - stdout, stderr, err = RunOVNNbctl("--wait=hv", "--", "--may-exist", "ls-add", name, "--", "set", "logical_switch", name, "other-config:subnet="+subnet, "external-ids:gateway_ip="+gatewayIPMask, "other-config:exclude_ips="+excludeIps) - } else { - stdout, stderr, err = RunOVNNbctl("--wait=hv", "--", "--may-exist", "ls-add", name, "--", "set", "logical_switch", name, "other-config:subnet="+subnet, "external-ids:gateway_ip="+gatewayIPMask) - } - if err != nil { - log.Error(err, "Failed to create a logical switch", "name", name, "stdout", stdout, "stderr", stderr) - return - } - return -} - -// CreateNetwork in OVN controller func (oc *Controller) CreateNetwork(cr *k8sv1alpha1.Network) error { var stdout, stderr string @@ -208,7 +213,7 @@ func (oc *Controller) CreateNetwork(cr *k8sv1alpha1.Network) error { gatewayIP := cr.Spec.Ipv4Subnets[0].Gateway excludeIps := cr.Spec.Ipv4Subnets[0].ExcludeIps - gatewayIPMask, err := oc.createOvnLS(name, subnet, gatewayIP, excludeIps) + gatewayIPMask, err := createOvnLS(name, subnet, gatewayIP, excludeIps) if err != nil { return err } @@ -266,7 +271,7 @@ func (oc *Controller) CreateProviderNetwork(cr *k8sv1alpha1.ProviderNetwork) err subnet := cr.Spec.Ipv4Subnets[0].Subnet gatewayIP := cr.Spec.Ipv4Subnets[0].Gateway excludeIps := cr.Spec.Ipv4Subnets[0].ExcludeIps - _, err := oc.createOvnLS(name, subnet, gatewayIP, excludeIps) + _, err := createOvnLS(name, subnet, gatewayIP, excludeIps) if err != nil { return err } @@ -339,7 +344,7 @@ func (oc *Controller) getGatewayFromSwitch(logicalSwitch string) (string, string return gatewayIP, mask, nil } -func (oc *Controller) addLogicalPortWithSwitch(pod *kapi.Pod, logicalSwitch, ipAddress, macAddress, interfaceName, netType string) (annotation string) { +func (oc *Controller) addLogicalPortWithSwitch(pod *kapi.Pod, logicalSwitch, ipAddress, macAddress, portName string) (annotation string) { var out, stderr string var err error var isStaticIP bool @@ -347,13 +352,6 @@ func (oc *Controller) addLogicalPortWithSwitch(pod *kapi.Pod, logicalSwitch, ipA return } - var portName string - if interfaceName != "" { - portName = fmt.Sprintf("%s_%s_%s", pod.Namespace, pod.Name, interfaceName) - } else { - return - } - log.V(1).Info("Creating logical port for on switch", "portName", portName, "logicalSwitch", logicalSwitch) if ipAddress != "" && macAddress != "" { diff --git a/internal/pkg/ovn/ovn_test.go b/internal/pkg/ovn/ovn_test.go deleted file mode 100644 index 5ea01d1..0000000 --- a/internal/pkg/ovn/ovn_test.go +++ /dev/null @@ -1,180 +0,0 @@ -package ovn - -import ( - "fmt" - "testing" - - "github.com/urfave/cli" - fakeexec "k8s.io/utils/exec/testing" - - "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "ovn4nfv-k8s-plugin/internal/pkg/config" - ovntest "ovn4nfv-k8s-plugin/internal/pkg/testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -func TestOvn(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "OVN/Pod Test Suite") -} - -var _ = AfterSuite(func() { -}) - -var _ = Describe("Add logical Port", func() { - var app *cli.App - - BeforeEach(func() { - app = cli.NewApp() - app.Name = "test" - app.Flags = config.Flags - - }) - - It("tests Pod", func() { - app.Action = func(ctx *cli.Context) error { - const ( - gwIP string = "10.1.1.1" - gwCIDR string = gwIP + "/24" - netName string = "ovn-prot-net" - portName string = "_ok_net0" - macIPAddress string = "0a:00:00:00:00:01 192.168.1.3" - ) - fakeCmds := ovntest.AddFakeCmd(nil, &ovntest.ExpectedCmd{ - Cmd: "ovn-nbctl --timeout=15 --data=bare --no-heading --columns=name find logical_switch " + "name=" + netName, - Output: netName, - }) - fakeCmds = ovntest.AddFakeCmdsNoOutputNoError(fakeCmds, []string{ - "ovn-nbctl --timeout=15 --wait=sb -- --may-exist lsp-add " + netName + " " + portName + " -- lsp-set-addresses " + portName + " dynamic -- set logical_switch_port " + portName + " external-ids:namespace= external-ids:logical_switch=" + netName + " external-ids:pod=true", - }) - - fakeCmds = ovntest.AddFakeCmd(fakeCmds, &ovntest.ExpectedCmd{ - Cmd: "ovn-nbctl --timeout=15 get logical_switch_port " + portName + " dynamic_addresses", - Output: macIPAddress, - }) - fakeCmds = ovntest.AddFakeCmd(fakeCmds, &ovntest.ExpectedCmd{ - Cmd: "ovn-nbctl --timeout=15 --if-exists get logical_switch " + netName + " external_ids:gateway_ip", - Output: gwCIDR, - }) - - fexec := &fakeexec.FakeExec{ - CommandScript: fakeCmds, - LookPathFunc: func(file string) (string, error) { - return fmt.Sprintf("/fake-bin/%s", file), nil - }, - } - oldSetupOvnUtils := SetupOvnUtils - // as we are exiting, revert ConfigureInterface back at end of function - defer func() { SetupOvnUtils = oldSetupOvnUtils }() - SetupOvnUtils = func() error { - return nil - } - ovnController, err := NewOvnController(fexec) - Expect(err).NotTo(HaveOccurred()) - - var ( - okPod = v1.Pod{ - TypeMeta: metav1.TypeMeta{ - Kind: "Pod", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "ok", - }, - Spec: v1.PodSpec{ - Containers: []v1.Container{ - { - Name: "by-name", - }, - {}, - }, - }, - } - ) - a := []map[string]interface{}{{"name": "ovn-prot-net", "interface": "net0"}} - ovnController.AddLogicalPorts(&okPod, a) - Expect(fexec.CommandCalls).To(Equal(len(fakeCmds))) - - return nil - } - - err := app.Run([]string{app.Name}) - Expect(err).NotTo(HaveOccurred()) - }) - - It("tests Pod provider", func() { - app.Action = func(ctx *cli.Context) error { - const ( - gwIP string = "10.1.1.1" - gwCIDR string = gwIP + "/24" - netName string = "ovn-prot-net" - portName string = "_ok_net0" - macIPAddress string = "0a:00:00:00:00:01 192.168.1.3/24" - ) - fakeCmds := ovntest.AddFakeCmd(nil, &ovntest.ExpectedCmd{ - Cmd: "ovn-nbctl --timeout=15 --data=bare --no-heading --columns=name find logical_switch " + "name=" + netName, - Output: netName, - }) - - fakeCmds = ovntest.AddFakeCmdsNoOutputNoError(fakeCmds, []string{ - "ovn-nbctl --timeout=15 --may-exist lsp-add " + netName + " " + portName + " -- lsp-set-addresses " + portName + " " + macIPAddress + " -- --if-exists clear logical_switch_port " + portName + " dynamic_addresses" + " -- set logical_switch_port " + portName + " external-ids:namespace= external-ids:logical_switch=" + netName + " external-ids:pod=true", - }) - - fakeCmds = ovntest.AddFakeCmd(fakeCmds, &ovntest.ExpectedCmd{ - Cmd: "ovn-nbctl --timeout=15 get logical_switch_port " + portName + " addresses", - Output: macIPAddress, - }) - - fakeCmds = ovntest.AddFakeCmd(fakeCmds, &ovntest.ExpectedCmd{ - Cmd: "ovn-nbctl --timeout=15 --if-exists get logical_switch " + netName + " external_ids:gateway_ip", - Output: gwCIDR, - }) - - fexec := &fakeexec.FakeExec{ - CommandScript: fakeCmds, - LookPathFunc: func(file string) (string, error) { - return fmt.Sprintf("/fake-bin/%s", file), nil - }, - } - oldSetupOvnUtils := SetupOvnUtils - // as we are exiting, revert ConfigureInterface back at end of function - defer func() { SetupOvnUtils = oldSetupOvnUtils }() - SetupOvnUtils = func() error { - return nil - } - ovnController, err := NewOvnController(fexec) - Expect(err).NotTo(HaveOccurred()) - var ( - okPod = v1.Pod{ - TypeMeta: metav1.TypeMeta{ - Kind: "Pod", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "ok", - }, - Spec: v1.PodSpec{ - Containers: []v1.Container{ - { - Name: "by-name", - }, - {}, - }, - }, - } - ) - a := []map[string]interface{}{{"name": "ovn-prot-net", "interface": "net0", "netType": "provider", "ipAddress": "192.168.1.3/24", "macAddress": "0a:00:00:00:00:01"}} - ovnController.AddLogicalPorts(&okPod, a) - Expect(fexec.CommandCalls).To(Equal(len(fakeCmds))) - - return nil - } - - err := app.Run([]string{app.Name}) - Expect(err).NotTo(HaveOccurred()) - }) - -}) diff --git a/internal/pkg/ovn/utils.go b/internal/pkg/ovn/utils.go index 3b3b53b..9b388b7 100644 --- a/internal/pkg/ovn/utils.go +++ b/internal/pkg/ovn/utils.go @@ -5,6 +5,7 @@ import ( "fmt" kexec "k8s.io/utils/exec" "os" + "reflect" "strings" "time" ) @@ -36,6 +37,13 @@ var SetupOvnUtils = func() error { log.Error(err, "Failed to initialize OVN Distributed Router") return err } + + log.Info("OVN Network", "OVN Default NW", Ovn4nfvDefaultNw, "OVN Subnet", ovnConf.Subnet, "OVN Gateway IP", ovnConf.GatewayIP, "OVN ExcludeIPs", ovnConf.ExcludeIPs) + _, err = createOvnLS(Ovn4nfvDefaultNw, ovnConf.Subnet, ovnConf.GatewayIP, ovnConf.ExcludeIPs) + if err != nil && !reflect.DeepEqual(err, fmt.Errorf("LS exists")) { + log.Error(err, "Failed to create ovn4nfvk8s default nw") + return err + } return nil } diff --git a/pkg/controller/pod/pod_controller.go b/pkg/controller/pod/pod_controller.go index 23a847e..75ed731 100644 --- a/pkg/controller/pod/pod_controller.go +++ b/pkg/controller/pod/pod_controller.go @@ -31,6 +31,7 @@ type nfnNetwork struct { Interface []map[string]interface{} "json:\"interface\"" } +var enableOvnDefaultIntf bool = true // Add creates a new Pod Controller and adds it to the Manager. The Manager will set fields on the Controller // and Start it when the Manager is Started. func Add(mgr manager.Manager) error { @@ -69,19 +70,19 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error { CreateFunc: func(e event.CreateEvent) bool { // The object doesn't contain annotation ,nfnNetworkAnnotation so the event will be // ignored. - annotaion := e.Meta.GetAnnotations() + /*annotaion := e.Meta.GetAnnotations() if _, ok := annotaion[nfnNetworkAnnotation]; !ok { return false - } + }*/ return true }, DeleteFunc: func(e event.DeleteEvent) bool { // The object doesn't contain annotation ,nfnNetworkAnnotation so the event will be // ignored. - annotaion := e.Meta.GetAnnotations() + /*annotaion := e.Meta.GetAnnotations() if _, ok := annotaion[nfnNetworkAnnotation]; !ok { return false - } + }*/ return true }, } @@ -121,10 +122,9 @@ func (r *ReconcilePod) Reconcile(request reconcile.Request) (reconcile.Result, e // Request object not found, could have been deleted after reconcile request. // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers. // Return and don't requeue - if instance.Name == "" || instance.Namespace == "" { - return reconcile.Result{}, nil - } + reqLogger.Info("Delete Pod", "request", request) r.deleteLogicalPorts(request.Name, request.Namespace) + reqLogger.Info("Exit Reconciling Pod") return reconcile.Result{}, nil } // Error reading the object - requeue the request. @@ -133,6 +133,10 @@ func (r *ReconcilePod) Reconcile(request reconcile.Request) (reconcile.Result, e if instance.Name == "" || instance.Namespace == "" { return reconcile.Result{}, nil } + if instance.Spec.HostNetwork { + return reconcile.Result{}, nil + } + err = r.addLogicalPorts(instance) if err != nil && err.Error() == "Failed to add ports" { // Requeue the object @@ -158,16 +162,22 @@ func (r *ReconcilePod) addLogicalPorts(pod *corev1.Pod) error { nfn, err := r.readPodAnnotation(pod) if err != nil { - return err + // No annotation for multiple interfaces + nfn = &nfnNetwork {Interface: nil} + if enableOvnDefaultIntf == true { + nfn.Type = "ovn4nfv" + } else { + return err + } } - + switch { case nfn.Type == "ovn4nfv": ovnCtl, err := ovn.GetOvnController() if err != nil { return err } - if _, ok := pod.Annotations[ovn.Ovn4nfvAnnotationTag]; ok { + if _, ok := pod.Annotations[ovn.Ovn4nfvAnnotationTag]; ok { return fmt.Errorf("Pod annotation found") } key, value := ovnCtl.AddLogicalPorts(pod, nfn.Interface) @@ -188,6 +198,7 @@ func (r *ReconcilePod) deleteLogicalPorts(name, namesapce string) error { if err != nil { return err } + log.Info("Calling DeleteLogicalPorts") ovnCtl.DeleteLogicalPorts(name, namesapce) return nil // Add other types here |