From 76ee297ee6ea8b10113cabba7b1f6401b4069a14 Mon Sep 17 00:00:00 2001 From: Dyanngg Date: Mon, 19 Dec 2022 20:56:54 -0800 Subject: [PATCH] Add ClusterSet scope for toServices field of Antrea-native policies (#4397) Adds a scope field for toServices feature in Antrea-native policy egress rules. When scope is set to ClusterSet, users can simply provide the name and Namespace of the exported Service, and Antrea will match rule with egress traffic intended for backends of the exported Service across all clusters in the ClusterSet. It is equivalent to putting the imported Service name (antrea-mc- [svcName]) in toServices field without setting scope. Signed-off-by: Dyanngg --- .../antrea/crds/clusternetworkpolicy.yaml | 2 + build/charts/antrea/crds/networkpolicy.yaml | 2 + build/yamls/antrea-aks.yml | 4 + build/yamls/antrea-crds.yml | 4 + build/yamls/antrea-eks.yml | 4 + build/yamls/antrea-gke.yml | 4 + build/yamls/antrea-ipsec.yml | 4 + build/yamls/antrea.yml | 4 + .../antrea-multicluster-leader-global.yml | 80 ++++++++++++------- ...cluster.crd.antrea.io_resourceexports.yaml | 40 ++++++---- ...cluster.crd.antrea.io_resourceimports.yaml | 40 ++++++---- .../controllers/multicluster/common/helper.go | 4 + .../acnp_resourceimport_controller.go | 6 +- .../commonarea/resourceimport_controller.go | 12 +-- multicluster/test/e2e/service_test.go | 2 +- pkg/apis/crd/v1alpha1/types.go | 23 ++++-- .../crd/v1alpha1/zz_generated.deepcopy.go | 18 ++++- .../networkpolicy/antreanetworkpolicy_test.go | 56 ++++++++++++- .../clusternetworkpolicy_test.go | 58 +++++++++++++- pkg/controller/networkpolicy/crd_utils.go | 28 ++++--- .../networkpolicy/networkpolicy_controller.go | 10 +-- pkg/controller/networkpolicy/validate.go | 2 +- pkg/controller/networkpolicy/validate_test.go | 16 ++-- test/e2e/antreapolicy_test.go | 4 +- test/e2e/utils/anp_spec_builder.go | 2 +- test/e2e/utils/cnp_spec_builder.go | 2 +- 26 files changed, 327 insertions(+), 104 deletions(-) diff --git a/build/charts/antrea/crds/clusternetworkpolicy.yaml b/build/charts/antrea/crds/clusternetworkpolicy.yaml index 59cdcd25430..4402a3a4548 100644 --- a/build/charts/antrea/crds/clusternetworkpolicy.yaml +++ b/build/charts/antrea/crds/clusternetworkpolicy.yaml @@ -638,6 +638,8 @@ spec: type: string namespace: type: string + scope: + type: string name: type: string enableLogging: diff --git a/build/charts/antrea/crds/networkpolicy.yaml b/build/charts/antrea/crds/networkpolicy.yaml index acac5cb696c..617100f054f 100644 --- a/build/charts/antrea/crds/networkpolicy.yaml +++ b/build/charts/antrea/crds/networkpolicy.yaml @@ -553,6 +553,8 @@ spec: type: string namespace: type: string + scope: + type: string name: type: string enableLogging: diff --git a/build/yamls/antrea-aks.yml b/build/yamls/antrea-aks.yml index 7f4665a275f..2992b4363b5 100644 --- a/build/yamls/antrea-aks.yml +++ b/build/yamls/antrea-aks.yml @@ -1016,6 +1016,8 @@ spec: type: string namespace: type: string + scope: + type: string name: type: string enableLogging: @@ -2081,6 +2083,8 @@ spec: type: string namespace: type: string + scope: + type: string name: type: string enableLogging: diff --git a/build/yamls/antrea-crds.yml b/build/yamls/antrea-crds.yml index 82e0fcb8c20..6cf3a870d2c 100644 --- a/build/yamls/antrea-crds.yml +++ b/build/yamls/antrea-crds.yml @@ -1009,6 +1009,8 @@ spec: type: string namespace: type: string + scope: + type: string name: type: string enableLogging: @@ -2062,6 +2064,8 @@ spec: type: string namespace: type: string + scope: + type: string name: type: string enableLogging: diff --git a/build/yamls/antrea-eks.yml b/build/yamls/antrea-eks.yml index 82a84eeca4d..b724225919b 100644 --- a/build/yamls/antrea-eks.yml +++ b/build/yamls/antrea-eks.yml @@ -1016,6 +1016,8 @@ spec: type: string namespace: type: string + scope: + type: string name: type: string enableLogging: @@ -2081,6 +2083,8 @@ spec: type: string namespace: type: string + scope: + type: string name: type: string enableLogging: diff --git a/build/yamls/antrea-gke.yml b/build/yamls/antrea-gke.yml index 2055bf2d0c5..73132f44bc0 100644 --- a/build/yamls/antrea-gke.yml +++ b/build/yamls/antrea-gke.yml @@ -1016,6 +1016,8 @@ spec: type: string namespace: type: string + scope: + type: string name: type: string enableLogging: @@ -2081,6 +2083,8 @@ spec: type: string namespace: type: string + scope: + type: string name: type: string enableLogging: diff --git a/build/yamls/antrea-ipsec.yml b/build/yamls/antrea-ipsec.yml index e1ef225c7d6..cd494d4ffe5 100644 --- a/build/yamls/antrea-ipsec.yml +++ b/build/yamls/antrea-ipsec.yml @@ -1016,6 +1016,8 @@ spec: type: string namespace: type: string + scope: + type: string name: type: string enableLogging: @@ -2081,6 +2083,8 @@ spec: type: string namespace: type: string + scope: + type: string name: type: string enableLogging: diff --git a/build/yamls/antrea.yml b/build/yamls/antrea.yml index 98c0784b91c..34bcec8fb18 100644 --- a/build/yamls/antrea.yml +++ b/build/yamls/antrea.yml @@ -1016,6 +1016,8 @@ spec: type: string namespace: type: string + scope: + type: string name: type: string enableLogging: @@ -2081,6 +2083,8 @@ spec: type: string namespace: type: string + scope: + type: string name: type: string enableLogging: diff --git a/multicluster/build/yamls/antrea-multicluster-leader-global.yml b/multicluster/build/yamls/antrea-multicluster-leader-global.yml index ecb8c699ca8..b361d645ec4 100644 --- a/multicluster/build/yamls/antrea-multicluster-leader-global.yml +++ b/multicluster/build/yamls/antrea-multicluster-leader-global.yml @@ -1438,19 +1438,25 @@ spec: type: array toServices: description: Rule is matched if traffic is intended for - a Service listed in this field. Currently only ClusterIP - types Services are supported in this field. This field - can only be used when AntreaProxy is enabled. This field - can't be used with To or Ports. If this field and To are - both empty or missing, this rule matches all destinations. + a Service listed in this field. Currently, only ClusterIP + types Services are supported in this field. When scope + is set to ClusterSet, it matches traffic intended for + a multi-cluster Service listed in this field. Service + name and Namespace provided should match the original + exported Service. This field can only be used when AntreaProxy + is enabled. This field can't be used with To or Ports. + If this field and To are both empty or missing, this rule + matches all destinations. items: - description: NamespacedName refers to a Namespace scoped - resource. All fields must be used together. + description: PeerService refers to a Service, which can + be a in-cluster Service or imported multi-cluster service. properties: name: type: string namespace: type: string + scope: + type: string type: object type: array required: @@ -2320,19 +2326,25 @@ spec: type: array toServices: description: Rule is matched if traffic is intended for - a Service listed in this field. Currently only ClusterIP - types Services are supported in this field. This field - can only be used when AntreaProxy is enabled. This field - can't be used with To or Ports. If this field and To are - both empty or missing, this rule matches all destinations. + a Service listed in this field. Currently, only ClusterIP + types Services are supported in this field. When scope + is set to ClusterSet, it matches traffic intended for + a multi-cluster Service listed in this field. Service + name and Namespace provided should match the original + exported Service. This field can only be used when AntreaProxy + is enabled. This field can't be used with To or Ports. + If this field and To are both empty or missing, this rule + matches all destinations. items: - description: NamespacedName refers to a Namespace scoped - resource. All fields must be used together. + description: PeerService refers to a Service, which can + be a in-cluster Service or imported multi-cluster service. properties: name: type: string namespace: type: string + scope: + type: string type: object type: array required: @@ -4118,19 +4130,25 @@ spec: type: array toServices: description: Rule is matched if traffic is intended for - a Service listed in this field. Currently only ClusterIP - types Services are supported in this field. This field - can only be used when AntreaProxy is enabled. This field - can't be used with To or Ports. If this field and To are - both empty or missing, this rule matches all destinations. + a Service listed in this field. Currently, only ClusterIP + types Services are supported in this field. When scope + is set to ClusterSet, it matches traffic intended for + a multi-cluster Service listed in this field. Service + name and Namespace provided should match the original + exported Service. This field can only be used when AntreaProxy + is enabled. This field can't be used with To or Ports. + If this field and To are both empty or missing, this rule + matches all destinations. items: - description: NamespacedName refers to a Namespace scoped - resource. All fields must be used together. + description: PeerService refers to a Service, which can + be a in-cluster Service or imported multi-cluster service. properties: name: type: string namespace: type: string + scope: + type: string type: object type: array required: @@ -5000,19 +5018,25 @@ spec: type: array toServices: description: Rule is matched if traffic is intended for - a Service listed in this field. Currently only ClusterIP - types Services are supported in this field. This field - can only be used when AntreaProxy is enabled. This field - can't be used with To or Ports. If this field and To are - both empty or missing, this rule matches all destinations. + a Service listed in this field. Currently, only ClusterIP + types Services are supported in this field. When scope + is set to ClusterSet, it matches traffic intended for + a multi-cluster Service listed in this field. Service + name and Namespace provided should match the original + exported Service. This field can only be used when AntreaProxy + is enabled. This field can't be used with To or Ports. + If this field and To are both empty or missing, this rule + matches all destinations. items: - description: NamespacedName refers to a Namespace scoped - resource. All fields must be used together. + description: PeerService refers to a Service, which can + be a in-cluster Service or imported multi-cluster service. properties: name: type: string namespace: type: string + scope: + type: string type: object type: array required: diff --git a/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceexports.yaml b/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceexports.yaml index 3855be8b332..fc5d680b9a5 100644 --- a/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceexports.yaml +++ b/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceexports.yaml @@ -1133,19 +1133,25 @@ spec: type: array toServices: description: Rule is matched if traffic is intended for - a Service listed in this field. Currently only ClusterIP - types Services are supported in this field. This field - can only be used when AntreaProxy is enabled. This field - can't be used with To or Ports. If this field and To are - both empty or missing, this rule matches all destinations. + a Service listed in this field. Currently, only ClusterIP + types Services are supported in this field. When scope + is set to ClusterSet, it matches traffic intended for + a multi-cluster Service listed in this field. Service + name and Namespace provided should match the original + exported Service. This field can only be used when AntreaProxy + is enabled. This field can't be used with To or Ports. + If this field and To are both empty or missing, this rule + matches all destinations. items: - description: NamespacedName refers to a Namespace scoped - resource. All fields must be used together. + description: PeerService refers to a Service, which can + be a in-cluster Service or imported multi-cluster service. properties: name: type: string namespace: type: string + scope: + type: string type: object type: array required: @@ -2015,19 +2021,25 @@ spec: type: array toServices: description: Rule is matched if traffic is intended for - a Service listed in this field. Currently only ClusterIP - types Services are supported in this field. This field - can only be used when AntreaProxy is enabled. This field - can't be used with To or Ports. If this field and To are - both empty or missing, this rule matches all destinations. + a Service listed in this field. Currently, only ClusterIP + types Services are supported in this field. When scope + is set to ClusterSet, it matches traffic intended for + a multi-cluster Service listed in this field. Service + name and Namespace provided should match the original + exported Service. This field can only be used when AntreaProxy + is enabled. This field can't be used with To or Ports. + If this field and To are both empty or missing, this rule + matches all destinations. items: - description: NamespacedName refers to a Namespace scoped - resource. All fields must be used together. + description: PeerService refers to a Service, which can + be a in-cluster Service or imported multi-cluster service. properties: name: type: string namespace: type: string + scope: + type: string type: object type: array required: diff --git a/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceimports.yaml b/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceimports.yaml index 1c104f6a11f..1e0dc7a17c2 100644 --- a/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceimports.yaml +++ b/multicluster/config/crd/bases/multicluster.crd.antrea.io_resourceimports.yaml @@ -1131,19 +1131,25 @@ spec: type: array toServices: description: Rule is matched if traffic is intended for - a Service listed in this field. Currently only ClusterIP - types Services are supported in this field. This field - can only be used when AntreaProxy is enabled. This field - can't be used with To or Ports. If this field and To are - both empty or missing, this rule matches all destinations. + a Service listed in this field. Currently, only ClusterIP + types Services are supported in this field. When scope + is set to ClusterSet, it matches traffic intended for + a multi-cluster Service listed in this field. Service + name and Namespace provided should match the original + exported Service. This field can only be used when AntreaProxy + is enabled. This field can't be used with To or Ports. + If this field and To are both empty or missing, this rule + matches all destinations. items: - description: NamespacedName refers to a Namespace scoped - resource. All fields must be used together. + description: PeerService refers to a Service, which can + be a in-cluster Service or imported multi-cluster service. properties: name: type: string namespace: type: string + scope: + type: string type: object type: array required: @@ -2013,19 +2019,25 @@ spec: type: array toServices: description: Rule is matched if traffic is intended for - a Service listed in this field. Currently only ClusterIP - types Services are supported in this field. This field - can only be used when AntreaProxy is enabled. This field - can't be used with To or Ports. If this field and To are - both empty or missing, this rule matches all destinations. + a Service listed in this field. Currently, only ClusterIP + types Services are supported in this field. When scope + is set to ClusterSet, it matches traffic intended for + a multi-cluster Service listed in this field. Service + name and Namespace provided should match the original + exported Service. This field can only be used when AntreaProxy + is enabled. This field can't be used with To or Ports. + If this field and To are both empty or missing, this rule + matches all destinations. items: - description: NamespacedName refers to a Namespace scoped - resource. All fields must be used together. + description: PeerService refers to a Service, which can + be a in-cluster Service or imported multi-cluster service. properties: name: type: string namespace: type: string + scope: + type: string type: object type: array required: diff --git a/multicluster/controllers/multicluster/common/helper.go b/multicluster/controllers/multicluster/common/helper.go index eeec1c9b9b0..80588e1ccdb 100644 --- a/multicluster/controllers/multicluster/common/helper.go +++ b/multicluster/controllers/multicluster/common/helper.go @@ -50,6 +50,10 @@ func NamespacedName(namespace, name string) string { return namespace + "/" + name } +func ToMCResourceName(originalResourceName string) string { + return AntreaMCSPrefix + originalResourceName +} + func StringExistsInSlice(slice []string, s string) bool { for _, item := range slice { if item == s { diff --git a/multicluster/controllers/multicluster/commonarea/acnp_resourceimport_controller.go b/multicluster/controllers/multicluster/commonarea/acnp_resourceimport_controller.go index e08c73b3bdb..2bf0cc22230 100644 --- a/multicluster/controllers/multicluster/commonarea/acnp_resourceimport_controller.go +++ b/multicluster/controllers/multicluster/commonarea/acnp_resourceimport_controller.go @@ -49,7 +49,7 @@ func (r *ResourceImportReconciler) handleResImpUpdateForClusterNetworkPolicy(ctx } acnpName := types.NamespacedName{ Namespace: "", - Name: common.AntreaMCSPrefix + resImp.Spec.Name, + Name: common.ToMCResourceName(resImp.Spec.Name), } klog.InfoS("Updating ACNP corresponding to ResourceImport", "acnp", acnpName.String(), "resourceimport", klog.KObj(resImp)) @@ -111,7 +111,7 @@ func (r *ResourceImportReconciler) handleResImpUpdateForClusterNetworkPolicy(ctx } func (r *ResourceImportReconciler) handleResImpDeleteForClusterNetworkPolicy(ctx context.Context, resImp *multiclusterv1alpha1.ResourceImport) (ctrl.Result, error) { - acnpName := common.AntreaMCSPrefix + resImp.Spec.Name + acnpName := common.ToMCResourceName(resImp.Spec.Name) klog.InfoS("Deleting ACNP corresponding to ResourceImport", "acnp", acnpName, "resourceimport", klog.KObj(resImp)) @@ -132,7 +132,7 @@ func (r *ResourceImportReconciler) handleResImpDeleteForClusterNetworkPolicy(ctx func getMCAntreaClusterPolicy(resImp *multiclusterv1alpha1.ResourceImport) *v1alpha1.ClusterNetworkPolicy { return &v1alpha1.ClusterNetworkPolicy{ ObjectMeta: metav1.ObjectMeta{ - Name: common.AntreaMCSPrefix + resImp.Spec.Name, + Name: common.ToMCResourceName(resImp.Spec.Name), Annotations: map[string]string{ common.AntreaMCACNPAnnotation: "true", }, diff --git a/multicluster/controllers/multicluster/commonarea/resourceimport_controller.go b/multicluster/controllers/multicluster/commonarea/resourceimport_controller.go index a4926346131..b73ff4e1f02 100644 --- a/multicluster/controllers/multicluster/commonarea/resourceimport_controller.go +++ b/multicluster/controllers/multicluster/commonarea/resourceimport_controller.go @@ -142,7 +142,7 @@ func (r *ResourceImportReconciler) Reconcile(ctx context.Context, req ctrl.Reque func (r *ResourceImportReconciler) handleResImpUpdateForService(ctx context.Context, resImp *multiclusterv1alpha1.ResourceImport) (ctrl.Result, error) { svcImpName := types.NamespacedName{Namespace: resImp.Spec.Namespace, Name: resImp.Spec.Name} - svcName := types.NamespacedName{Namespace: resImp.Spec.Namespace, Name: common.AntreaMCSPrefix + resImp.Spec.Name} + svcName := types.NamespacedName{Namespace: resImp.Spec.Namespace, Name: common.ToMCResourceName(resImp.Spec.Name)} klog.InfoS("Updating Service and ServiceImport corresponding to ResourceImport", "service", svcName.String(), "serviceimport", svcImpName.String(), "resourceimport", klog.KObj(resImp)) @@ -224,14 +224,14 @@ func (r *ResourceImportReconciler) handleResImpUpdateForService(ctx context.Cont func (r *ResourceImportReconciler) handleResImpDeleteForService(ctx context.Context, resImp *multiclusterv1alpha1.ResourceImport) (ctrl.Result, error) { svcImpName := common.NamespacedName(resImp.Spec.Namespace, resImp.Spec.Name) - svcName := common.NamespacedName(resImp.Spec.Namespace, common.AntreaMCSPrefix+resImp.Spec.Name) + svcName := common.NamespacedName(resImp.Spec.Namespace, common.ToMCResourceName(resImp.Spec.Name)) klog.InfoS("Deleting Service and ServiceImport corresponding to ResourceImport", "service", svcName, "serviceImport", svcImpName, "resourceimport", klog.KObj(resImp)) svc := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ Namespace: resImp.Spec.Namespace, - Name: common.AntreaMCSPrefix + resImp.Spec.Name, + Name: common.ToMCResourceName(resImp.Spec.Name), }, } err := r.localClusterClient.Delete(ctx, svc, &client.DeleteOptions{}) @@ -256,7 +256,7 @@ func (r *ResourceImportReconciler) handleResImpDeleteForService(ctx context.Cont } func (r *ResourceImportReconciler) handleResImpUpdateForEndpoints(ctx context.Context, resImp *multiclusterv1alpha1.ResourceImport) (ctrl.Result, error) { - epName := common.AntreaMCSPrefix + resImp.Spec.Name + epName := common.ToMCResourceName(resImp.Spec.Name) epNamespaced := types.NamespacedName{Namespace: resImp.Spec.Namespace, Name: epName} klog.InfoS("Updating Endpoints corresponding to ResourceImport", "endpoints", epNamespaced.String(), "resourceimport", klog.KObj(resImp)) @@ -311,7 +311,7 @@ func (r *ResourceImportReconciler) handleResImpUpdateForEndpoints(ctx context.Co } func (r *ResourceImportReconciler) handleResImpDeleteForEndpoints(ctx context.Context, resImp *multiclusterv1alpha1.ResourceImport) (ctrl.Result, error) { - epName := common.AntreaMCSPrefix + resImp.Spec.Name + epName := common.ToMCResourceName(resImp.Spec.Name) epNamespacedName := common.NamespacedName(resImp.Spec.Namespace, epName) klog.InfoS("Deleting Endpoints corresponding to ResourceImport", "endpoints", epNamespacedName, "resourceimport", klog.KObj(resImp)) @@ -342,7 +342,7 @@ func getMCService(resImp *multiclusterv1alpha1.ResourceImport) *corev1.Service { } mcs := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ - Name: common.AntreaMCSPrefix + resImp.Spec.Name, + Name: common.ToMCResourceName(resImp.Spec.Name), Namespace: resImp.Spec.Namespace, Annotations: map[string]string{ common.AntreaMCServiceAnnotation: "true", diff --git a/multicluster/test/e2e/service_test.go b/multicluster/test/e2e/service_test.go index ce7c731acca..1cb3572d448 100644 --- a/multicluster/test/e2e/service_test.go +++ b/multicluster/test/e2e/service_test.go @@ -175,7 +175,7 @@ func (data *MCTestData) testANPToServices(t *testing.T) { anpBuilder = anpBuilder.SetName(multiClusterTestNamespace, "block-west-exported-service"). SetPriority(1.0). SetAppliedToGroup([]e2euttils.ANPAppliedToSpec{{PodSelector: map[string]string{"app": "client"}}}). - AddToServicesRule([]crdv1alpha1.NamespacedName{{ + AddToServicesRule([]crdv1alpha1.PeerService{{ Name: mcWestClusterTestService, Namespace: multiClusterTestNamespace}, }, "", nil, crdv1alpha1.RuleActionDrop) diff --git a/pkg/apis/crd/v1alpha1/types.go b/pkg/apis/crd/v1alpha1/types.go index 5448e20305d..e21af92ed98 100644 --- a/pkg/apis/crd/v1alpha1/types.go +++ b/pkg/apis/crd/v1alpha1/types.go @@ -415,12 +415,15 @@ type Rule struct { // +optional To []NetworkPolicyPeer `json:"to,omitempty"` // Rule is matched if traffic is intended for a Service listed in this field. - // Currently only ClusterIP types Services are supported in this field. This field - // can only be used when AntreaProxy is enabled. This field can't be used with To - // or Ports. If this field and To are both empty or missing, this rule matches all - // destinations. - // +optional - ToServices []NamespacedName `json:"toServices,omitempty"` + // Currently, only ClusterIP types Services are supported in this field. + // When scope is set to ClusterSet, it matches traffic intended for a multi-cluster + // Service listed in this field. Service name and Namespace provided should match + // the original exported Service. + // This field can only be used when AntreaProxy is enabled. This field can't be used + // with To or Ports. If this field and To are both empty or missing, this rule matches + // all destinations. + // +optional + ToServices []PeerService `json:"toServices,omitempty"` // Name describes the intention of this rule. // Name should be unique within the policy. // +optional @@ -706,6 +709,14 @@ type NamespacedName struct { Namespace string `json:"namespace,omitempty"` } +// PeerService refers to a Service, which can be a in-cluster Service or +// imported multi-cluster service. +type PeerService struct { + Name string `json:"name,omitempty"` + Namespace string `json:"namespace,omitempty"` + Scope PeerScope `json:"scope,omitempty"` +} + // NetworkPolicyProtocol defines additional protocols that are not supported by // `ports`. All fields should be used as a standalone field. type NetworkPolicyProtocol struct { diff --git a/pkg/apis/crd/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/crd/v1alpha1/zz_generated.deepcopy.go index 4da65431320..064ade764eb 100644 --- a/pkg/apis/crd/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/crd/v1alpha1/zz_generated.deepcopy.go @@ -865,6 +865,22 @@ func (in *PeerNamespaces) DeepCopy() *PeerNamespaces { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PeerService) DeepCopyInto(out *PeerService) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PeerService. +func (in *PeerService) DeepCopy() *PeerService { + if in == nil { + return nil + } + out := new(PeerService) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Rule) DeepCopyInto(out *Rule) { *out = *in @@ -910,7 +926,7 @@ func (in *Rule) DeepCopyInto(out *Rule) { } if in.ToServices != nil { in, out := &in.ToServices, &out.ToServices - *out = make([]NamespacedName, len(*in)) + *out = make([]PeerService, len(*in)) copy(*out, *in) } if in.AppliedTo != nil { diff --git a/pkg/controller/networkpolicy/antreanetworkpolicy_test.go b/pkg/controller/networkpolicy/antreanetworkpolicy_test.go index e4f155e814e..032b8ed7303 100644 --- a/pkg/controller/networkpolicy/antreanetworkpolicy_test.go +++ b/pkg/controller/networkpolicy/antreanetworkpolicy_test.go @@ -22,6 +22,7 @@ import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "antrea.io/antrea/multicluster/controllers/multicluster/common" "antrea.io/antrea/pkg/apis/controlplane" crdv1alpha1 "antrea.io/antrea/pkg/apis/crd/v1alpha1" antreatypes "antrea.io/antrea/pkg/controller/types" @@ -407,7 +408,7 @@ func TestProcessAntreaNetworkPolicy(t *testing.T) { Priority: p10, Egress: []crdv1alpha1.Rule{ { - ToServices: []crdv1alpha1.NamespacedName{ + ToServices: []crdv1alpha1.PeerService{ { Namespace: "ns5", Name: "svc1", @@ -449,6 +450,59 @@ func TestProcessAntreaNetworkPolicy(t *testing.T) { expectedAppliedToGroups: 1, expectedAddressGroups: 0, }, + { + name: "rules-with-to-mc-services", + inputPolicy: &crdv1alpha1.NetworkPolicy{ + ObjectMeta: metav1.ObjectMeta{Namespace: "ns5", Name: "npE2", UID: "uidE2"}, + Spec: crdv1alpha1.NetworkPolicySpec{ + AppliedTo: []crdv1alpha1.AppliedTo{ + {PodSelector: &selectorA}, + }, + Priority: p10, + Egress: []crdv1alpha1.Rule{ + { + ToServices: []crdv1alpha1.PeerService{ + { + Name: "svc1", + Scope: crdv1alpha1.ScopeClusterSet, + }, + }, + Action: &allowAction, + }, + }, + }, + }, + expectedPolicy: &antreatypes.NetworkPolicy{ + UID: "uidE2", + Name: "uidE2", + SourceRef: &controlplane.NetworkPolicyReference{ + Type: controlplane.AntreaNetworkPolicy, + Namespace: "ns5", + Name: "npE2", + UID: "uidE2", + }, + Priority: &p10, + TierPriority: &DefaultTierPriority, + Rules: []controlplane.NetworkPolicyRule{ + { + Direction: controlplane.DirectionOut, + To: controlplane.NetworkPolicyPeer{ + ToServices: []controlplane.ServiceReference{ + { + Namespace: "ns5", + Name: common.ToMCResourceName("svc1"), + }, + }, + }, + Priority: 0, + Action: &allowAction, + }, + }, + AppliedToGroups: []string{getNormalizedUID(antreatypes.NewGroupSelector("ns5", &selectorA, nil, nil, nil).NormalizedName)}, + }, + expectedAppliedToGroups: 1, + expectedAddressGroups: 0, + }, { name: "rules-with-nodeSelector", inputPolicy: &crdv1alpha1.NetworkPolicy{ diff --git a/pkg/controller/networkpolicy/clusternetworkpolicy_test.go b/pkg/controller/networkpolicy/clusternetworkpolicy_test.go index cf0f69a343b..d47e155c9c1 100644 --- a/pkg/controller/networkpolicy/clusternetworkpolicy_test.go +++ b/pkg/controller/networkpolicy/clusternetworkpolicy_test.go @@ -26,6 +26,7 @@ import ( "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/sets" + "antrea.io/antrea/multicluster/controllers/multicluster/common" "antrea.io/antrea/pkg/apis/controlplane" crdv1alpha1 "antrea.io/antrea/pkg/apis/crd/v1alpha1" crdv1alpha3 "antrea.io/antrea/pkg/apis/crd/v1alpha3" @@ -936,7 +937,7 @@ func TestProcessClusterNetworkPolicy(t *testing.T) { Priority: p10, Egress: []crdv1alpha1.Rule{ { - ToServices: []crdv1alpha1.NamespacedName{ + ToServices: []crdv1alpha1.PeerService{ { Namespace: "nsA", Name: "svcA", @@ -977,6 +978,59 @@ func TestProcessClusterNetworkPolicy(t *testing.T) { expectedAppliedToGroups: 1, expectedAddressGroups: 0, }, + { + name: "rule-with-to-mc-service", + inputPolicy: &crdv1alpha1.ClusterNetworkPolicy{ + ObjectMeta: metav1.ObjectMeta{Name: "cnpM", UID: "uidM"}, + Spec: crdv1alpha1.ClusterNetworkPolicySpec{ + AppliedTo: []crdv1alpha1.AppliedTo{ + {PodSelector: &selectorA}, + }, + Priority: p10, + Egress: []crdv1alpha1.Rule{ + { + ToServices: []crdv1alpha1.PeerService{ + { + Namespace: "nsA", + Name: "svcA", + Scope: crdv1alpha1.ScopeClusterSet, + }, + }, + Action: &dropAction, + }, + }, + }, + }, + expectedPolicy: &antreatypes.NetworkPolicy{ + UID: "uidM", + Name: "uidM", + SourceRef: &controlplane.NetworkPolicyReference{ + Type: controlplane.AntreaClusterNetworkPolicy, + Name: "cnpM", + UID: "uidM", + }, + Priority: &p10, + TierPriority: &DefaultTierPriority, + Rules: []controlplane.NetworkPolicyRule{ + { + Direction: controlplane.DirectionOut, + To: controlplane.NetworkPolicyPeer{ + ToServices: []controlplane.ServiceReference{ + { + Namespace: "nsA", + Name: common.ToMCResourceName("svcA"), + }, + }, + }, + Priority: 0, + Action: &dropAction, + }, + }, + AppliedToGroups: []string{getNormalizedUID(antreatypes.NewGroupSelector("", &selectorA, nil, nil, nil).NormalizedName)}, + }, + expectedAppliedToGroups: 1, + expectedAddressGroups: 0, + }, { name: "applied-to-with-service-account-namespaced-name", inputPolicy: &crdv1alpha1.ClusterNetworkPolicy{ @@ -993,7 +1047,7 @@ func TestProcessClusterNetworkPolicy(t *testing.T) { Priority: p10, Egress: []crdv1alpha1.Rule{ { - ToServices: []crdv1alpha1.NamespacedName{ + ToServices: []crdv1alpha1.PeerService{ { Namespace: "nsA", Name: "svcA", diff --git a/pkg/controller/networkpolicy/crd_utils.go b/pkg/controller/networkpolicy/crd_utils.go index 0319ffc9675..2a359e6210b 100644 --- a/pkg/controller/networkpolicy/crd_utils.go +++ b/pkg/controller/networkpolicy/crd_utils.go @@ -24,6 +24,7 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/klog/v2" + "antrea.io/antrea/multicluster/controllers/multicluster/common" "antrea.io/antrea/pkg/apis/controlplane" "antrea.io/antrea/pkg/apis/crd/v1alpha1" crdv1alpha3 "antrea.io/antrea/pkg/apis/crd/v1alpha3" @@ -198,7 +199,7 @@ func (n *NetworkPolicyController) toAntreaPeerForCRD(peers []v1alpha1.NetworkPol } } var labelIdentities []uint32 - if n.multiclusterEnabled { + if n.stretchNPEnabled { labelIdentities = n.labelIdentityInterface.SetPolicySelectors(clusterSetScopeSelectors, internalNetworkPolicyKeyFunc(np)) } return &controlplane.NetworkPolicyPeer{AddressGroups: getAddressGroupNames(addressGroups), IPBlocks: ipBlocks, FQDNs: fqdns, LabelIdentities: labelIdentities}, addressGroups @@ -216,20 +217,27 @@ func (n *NetworkPolicyController) toNamespacedPeerForCRD(peers []v1alpha1.Networ return &controlplane.NetworkPolicyPeer{AddressGroups: getAddressGroupNames(addressGroups)}, addressGroups } -// svcRefToPeerForCRD creates an Antrea controlplane NetworkPolicyPeer from -// ServiceReference in ToServices field. For ANP, we will use the -// defaultNamespace(policy Namespace) as the Namespace of ServiceReference that -// doesn't set Namespace. -func (n *NetworkPolicyController) svcRefToPeerForCRD(svcRefs []v1alpha1.NamespacedName, defaultNamespace string) *controlplane.NetworkPolicyPeer { +// svcRefToPeerForCRD creates an Antrea controlplane NetworkPolicyPeer from ServiceReferences in ToServices +// or ToMulticlusterServices field of a crdv1alpha1 NetworkPolicyPeer. For ANP NetworkPolicyPeers, if +// Namespace is not provided in the ServiceReference, the policy's Namespace will be assumed. +func (n *NetworkPolicyController) svcRefToPeerForCRD(svcRefs []v1alpha1.PeerService, defaultNamespace string) *controlplane.NetworkPolicyPeer { var controlplaneSvcRefs []controlplane.ServiceReference for _, svcRef := range svcRefs { - curNS := defaultNamespace + svcNS, svcName := defaultNamespace, svcRef.Name if svcRef.Namespace != "" { - curNS = svcRef.Namespace + svcNS = svcRef.Namespace + } + if svcRef.Scope == v1alpha1.ScopeClusterSet { + if n.stretchNPEnabled { + svcName = common.ToMCResourceName(svcName) + } else { + klog.Error("Unable to process ClusterSet scoped service reference when stretched networkpolicy is not enabled") + continue + } } controlplaneSvcRefs = append(controlplaneSvcRefs, controlplane.ServiceReference{ - Namespace: curNS, - Name: svcRef.Name, + Namespace: svcNS, + Name: svcName, }) } return &controlplane.NetworkPolicyPeer{ToServices: controlplaneSvcRefs} diff --git a/pkg/controller/networkpolicy/networkpolicy_controller.go b/pkg/controller/networkpolicy/networkpolicy_controller.go index 63eeebd76a9..5a3a4a60b0f 100644 --- a/pkg/controller/networkpolicy/networkpolicy_controller.go +++ b/pkg/controller/networkpolicy/networkpolicy_controller.go @@ -240,9 +240,9 @@ type NetworkPolicyController struct { groupingInterfaceSynced func() bool labelIdentityInterface labelidentity.Interface - // Enable Multicluster which allow Antrea-native policies to select peer + // Enable Stretched Networkpolicy feature which allow Antrea-native policies to select peer // from other clusters in a ClusterSet. - multiclusterEnabled bool + stretchNPEnabled bool // heartbeatCh is an internal channel for testing. It's used to know whether all tasks have been // processed, and to count executions of each function. heartbeatCh chan heartbeat @@ -391,7 +391,7 @@ func NewNetworkPolicyController(kubeClient clientset.Interface, appliedToGroupStore storage.Interface, internalNetworkPolicyStore storage.Interface, internalGroupStore storage.Interface, - multiclusterEnabled bool) *NetworkPolicyController { + stretchedNPEnabled bool) *NetworkPolicyController { n := &NetworkPolicyController{ kubeClient: kubeClient, crdClient: crdClient, @@ -409,7 +409,7 @@ func NewNetworkPolicyController(kubeClient clientset.Interface, groupingInterface: groupingInterface, groupingInterfaceSynced: groupingInterface.HasSynced, labelIdentityInterface: labelIdentityInterface, - multiclusterEnabled: multiclusterEnabled, + stretchNPEnabled: stretchedNPEnabled, } n.groupingInterface.AddEventHandler(appliedToGroupType, n.enqueueAppliedToGroup) n.groupingInterface.AddEventHandler(addressGroupType, n.enqueueAddressGroup) @@ -1570,7 +1570,7 @@ func (n *NetworkPolicyController) deleteInternalNetworkPolicy(name string) { internalNetworkPolicy := obj.(*antreatypes.NetworkPolicy) n.internalNetworkPolicyStore.Delete(internalNetworkPolicy.Name) n.cleanupOrphanGroups(internalNetworkPolicy) - if n.multiclusterEnabled && internalNetworkPolicy.SourceRef.Type != controlplane.K8sNetworkPolicy { + if n.stretchNPEnabled && internalNetworkPolicy.SourceRef.Type != controlplane.K8sNetworkPolicy { n.labelIdentityInterface.DeletePolicySelectors(internalNetworkPolicy.Name) } // Enqueue AddressGroups previously used by this NetworkPolicy as their span may change due to the removal. diff --git a/pkg/controller/networkpolicy/validate.go b/pkg/controller/networkpolicy/validate.go index f33e5720d0b..3fd62ad0d24 100644 --- a/pkg/controller/networkpolicy/validate.go +++ b/pkg/controller/networkpolicy/validate.go @@ -589,7 +589,7 @@ func (v *antreaPolicyValidator) validatePeers(ingress, egress []crdv1alpha1.Rule return fmt.Sprintf("`toServices` can only be used when AntreaProxy is enabled"), false } if (rule.To != nil && len(rule.To) > 0) || rule.Ports != nil || rule.Protocols != nil { - return fmt.Sprintf("`toServices` can't be used with `to`, `ports` or `protocols`"), false + return fmt.Sprintf("`toServices` cannot be used with `to`, `ports` or `protocols`"), false } } msg, isValid := checkPeers(rule.To) diff --git a/pkg/controller/networkpolicy/validate_test.go b/pkg/controller/networkpolicy/validate_test.go index 88557debfc2..8932c264cc8 100644 --- a/pkg/controller/networkpolicy/validate_test.go +++ b/pkg/controller/networkpolicy/validate_test.go @@ -696,7 +696,7 @@ func TestValidateAntreaPolicy(t *testing.T) { }, }, }, - ToServices: []crdv1alpha1.NamespacedName{ + ToServices: []crdv1alpha1.PeerService{ { Name: "foo", Namespace: "bar", @@ -706,7 +706,7 @@ func TestValidateAntreaPolicy(t *testing.T) { }, }, }, - expectedReason: "`toServices` can't be used with `to`, `ports` or `protocols`", + expectedReason: "`toServices` cannot be used with `to`, `ports` or `protocols`", }, { name: "acnp-toservice-set-with-ports", @@ -730,7 +730,7 @@ func TestValidateAntreaPolicy(t *testing.T) { Port: &int80, }, }, - ToServices: []crdv1alpha1.NamespacedName{ + ToServices: []crdv1alpha1.PeerService{ { Name: "foo", Namespace: "bar", @@ -740,7 +740,7 @@ func TestValidateAntreaPolicy(t *testing.T) { }, }, }, - expectedReason: "`toServices` can't be used with `to`, `ports` or `protocols`", + expectedReason: "`toServices` cannot be used with `to`, `ports` or `protocols`", }, { name: "acnp-toservice-set-with-protocols", @@ -764,7 +764,7 @@ func TestValidateAntreaPolicy(t *testing.T) { ICMP: &crdv1alpha1.ICMPProtocol{}, }, }, - ToServices: []crdv1alpha1.NamespacedName{ + ToServices: []crdv1alpha1.PeerService{ { Name: "foo", Namespace: "bar", @@ -774,7 +774,7 @@ func TestValidateAntreaPolicy(t *testing.T) { }, }, }, - expectedReason: "`toServices` can't be used with `to`, `ports` or `protocols`", + expectedReason: "`toServices` cannot be used with `to`, `ports` or `protocols`", }, { name: "acnp-toservice-alone", @@ -793,7 +793,7 @@ func TestValidateAntreaPolicy(t *testing.T) { Egress: []crdv1alpha1.Rule{ { Action: &allowAction, - ToServices: []crdv1alpha1.NamespacedName{ + ToServices: []crdv1alpha1.PeerService{ { Name: "foo", Namespace: "bar", @@ -1388,7 +1388,7 @@ func TestValidateAntreaPolicy(t *testing.T) { }, }, }, - ToServices: []crdv1alpha1.NamespacedName{ + ToServices: []crdv1alpha1.PeerService{ { Name: "foo", Namespace: "bar", diff --git a/test/e2e/antreapolicy_test.go b/test/e2e/antreapolicy_test.go index 5d0d98e2b4e..02713c09e55 100644 --- a/test/e2e/antreapolicy_test.go +++ b/test/e2e/antreapolicy_test.go @@ -3334,12 +3334,12 @@ func testToServices(t *testing.T) { services = append(services, ipv6Svc) } - var svcRefs []crdv1alpha1.NamespacedName + var svcRefs []crdv1alpha1.PeerService var builtSvcs []*v1.Service for _, service := range services { builtSvc, _ := k8sUtils.CreateOrUpdateService(service) failOnError(waitForResourceReady(t, timeout, service), t) - svcRefs = append(svcRefs, crdv1alpha1.NamespacedName{ + svcRefs = append(svcRefs, crdv1alpha1.PeerService{ Name: service.Name, Namespace: service.Namespace, }) diff --git a/test/e2e/utils/anp_spec_builder.go b/test/e2e/utils/anp_spec_builder.go index fc94cbe9324..dc350e1ca81 100644 --- a/test/e2e/utils/anp_spec_builder.go +++ b/test/e2e/utils/anp_spec_builder.go @@ -187,7 +187,7 @@ func (b *AntreaNetworkPolicySpecBuilder) AddEgress(protoc AntreaPolicyProtocol, return b } -func (b *AntreaNetworkPolicySpecBuilder) AddToServicesRule(svcRefs []crdv1alpha1.NamespacedName, +func (b *AntreaNetworkPolicySpecBuilder) AddToServicesRule(svcRefs []crdv1alpha1.PeerService, name string, ruleAppliedToSpecs []ANPAppliedToSpec, action crdv1alpha1.RuleAction) *AntreaNetworkPolicySpecBuilder { var appliedTos []crdv1alpha1.AppliedTo for _, at := range ruleAppliedToSpecs { diff --git a/test/e2e/utils/cnp_spec_builder.go b/test/e2e/utils/cnp_spec_builder.go index 9907e56d96c..761e2f9e0c4 100644 --- a/test/e2e/utils/cnp_spec_builder.go +++ b/test/e2e/utils/cnp_spec_builder.go @@ -244,7 +244,7 @@ func (b *ClusterNetworkPolicySpecBuilder) AddFQDNRule(fqdn string, return b } -func (b *ClusterNetworkPolicySpecBuilder) AddToServicesRule(svcRefs []crdv1alpha1.NamespacedName, +func (b *ClusterNetworkPolicySpecBuilder) AddToServicesRule(svcRefs []crdv1alpha1.PeerService, name string, ruleAppliedToSpecs []ACNPAppliedToSpec, action crdv1alpha1.RuleAction) *ClusterNetworkPolicySpecBuilder { var appliedTos []crdv1alpha1.AppliedTo for _, at := range ruleAppliedToSpecs {