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 {