diff --git a/pkg/apis/networking/types.go b/pkg/apis/networking/types.go index ae37fcd5e26..b92e03295bc 100644 --- a/pkg/apis/networking/types.go +++ b/pkg/apis/networking/types.go @@ -159,22 +159,28 @@ type IPBlock struct { Except []string } -// NetworkPolicyPeer describes a peer to allow traffic from. Exactly one of its fields -// must be specified. +// NetworkPolicyPeer describes a peer to allow traffic from. type NetworkPolicyPeer struct { - // This is a label selector which selects Pods in this namespace. This field - // follows standard label selector semantics. If present but empty, this selector - // selects all pods in this namespace. + // This is a label selector which selects Pods. This field follows standard label + // selector semantics; if present but empty, it selects all pods. + // + // If NamespaceSelector is also set, then the NetworkPolicyPeer as a whole selects + // the Pods matching PodSelector in the Namespaces selected by NamespaceSelector. + // Otherwise it selects the Pods matching PodSelector in the policy's own Namespace. // +optional PodSelector *metav1.LabelSelector - // Selects Namespaces using cluster scoped-labels. This matches all pods in all - // namespaces selected by this label selector. This field follows standard label - // selector semantics. If present but empty, this selector selects all namespaces. + // Selects Namespaces using cluster-scoped labels. This field follows standard label + // selector semantics; if present but empty, it selects all namespaces. + // + // If PodSelector is also set, then the NetworkPolicyPeer as a whole selects + // the Pods matching PodSelector in the Namespaces selected by NamespaceSelector. + // Otherwise it selects all Pods in the Namespaces selected by NamespaceSelector. // +optional NamespaceSelector *metav1.LabelSelector - // IPBlock defines policy on a particular IPBlock + // IPBlock defines policy on a particular IPBlock. If this field is set then + // neither of the other fields can be. // +optional IPBlock *IPBlock } diff --git a/pkg/apis/networking/validation/validation.go b/pkg/apis/networking/validation/validation.go index b96d9c3f055..dc1934ca17e 100644 --- a/pkg/apis/networking/validation/validation.go +++ b/pkg/apis/networking/validation/validation.go @@ -75,8 +75,8 @@ func ValidateNetworkPolicyPeer(peer *networking.NetworkPolicyPeer, peerPath *fie if numPeers == 0 { allErrs = append(allErrs, field.Required(peerPath, "must specify a peer")) - } else if numPeers > 1 { - allErrs = append(allErrs, field.Forbidden(peerPath, "may not specify more than 1 peer")) + } else if numPeers > 1 && peer.IPBlock != nil { + allErrs = append(allErrs, field.Forbidden(peerPath, "may not specify both ipBlock and another peer")) } return allErrs diff --git a/pkg/apis/networking/validation/validation_test.go b/pkg/apis/networking/validation/validation_test.go index 3af353d8ce2..67ebc24f915 100644 --- a/pkg/apis/networking/validation/validation_test.go +++ b/pkg/apis/networking/validation/validation_test.go @@ -122,6 +122,28 @@ func TestValidateNetworkPolicy(t *testing.T) { }, }, }, + { + ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"}, + Spec: networking.NetworkPolicySpec{ + PodSelector: metav1.LabelSelector{ + MatchLabels: map[string]string{"a": "b"}, + }, + Ingress: []networking.NetworkPolicyIngressRule{ + { + From: []networking.NetworkPolicyPeer{ + { + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"c": "d"}, + }, + PodSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"e": "f"}, + }, + }, + }, + }, + }, + }, + }, { ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: networking.NetworkPolicySpec{ @@ -256,7 +278,7 @@ func TestValidateNetworkPolicy(t *testing.T) { invalidSelector := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"} errorCases := map[string]networking.NetworkPolicy{ - "namespaceSelector and podSelector": { + "namespaceSelector and ipBlock": { ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: networking.NetworkPolicySpec{ PodSelector: metav1.LabelSelector{ @@ -266,16 +288,25 @@ func TestValidateNetworkPolicy(t *testing.T) { { From: []networking.NetworkPolicyPeer{ { - PodSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"c": "d"}, - }, NamespaceSelector: &metav1.LabelSelector{ MatchLabels: map[string]string{"c": "d"}, }, + IPBlock: &networking.IPBlock{ + CIDR: "192.168.0.0/16", + Except: []string{"192.168.3.0/24", "192.168.4.0/24"}, + }, }, }, }, }, + }, + }, + "podSelector and ipBlock": { + ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"}, + Spec: networking.NetworkPolicySpec{ + PodSelector: metav1.LabelSelector{ + MatchLabels: map[string]string{"a": "b"}, + }, Egress: []networking.NetworkPolicyEgressRule{ { To: []networking.NetworkPolicyPeer{ @@ -283,8 +314,9 @@ func TestValidateNetworkPolicy(t *testing.T) { PodSelector: &metav1.LabelSelector{ MatchLabels: map[string]string{"c": "d"}, }, - NamespaceSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"c": "d"}, + IPBlock: &networking.IPBlock{ + CIDR: "192.168.0.0/16", + Except: []string{"192.168.3.0/24", "192.168.4.0/24"}, }, }, }, diff --git a/staging/src/k8s.io/api/extensions/v1beta1/types.go b/staging/src/k8s.io/api/extensions/v1beta1/types.go index c3d9f72d734..d3bd165b8d1 100644 --- a/staging/src/k8s.io/api/extensions/v1beta1/types.go +++ b/staging/src/k8s.io/api/extensions/v1beta1/types.go @@ -1256,22 +1256,26 @@ type IPBlock struct { // DEPRECATED 1.9 - This group version of NetworkPolicyPeer is deprecated by networking/v1/NetworkPolicyPeer. type NetworkPolicyPeer struct { - // Exactly one of the following must be specified. - - // This is a label selector which selects Pods in this namespace. - // This field follows standard label selector semantics. - // If present but empty, this selector selects all pods in this namespace. + // This is a label selector which selects Pods. This field follows standard label + // selector semantics; if present but empty, it selects all pods. + // + // If NamespaceSelector is also set, then the NetworkPolicyPeer as a whole selects + // the Pods matching PodSelector in the Namespaces selected by NamespaceSelector. + // Otherwise it selects the Pods matching PodSelector in the policy's own Namespace. // +optional PodSelector *metav1.LabelSelector `json:"podSelector,omitempty" protobuf:"bytes,1,opt,name=podSelector"` - // Selects Namespaces using cluster scoped-labels. This - // matches all pods in all namespaces selected by this label selector. - // This field follows standard label selector semantics. - // If present but empty, this selector selects all namespaces. + // Selects Namespaces using cluster-scoped labels. This field follows standard label + // selector semantics; if present but empty, it selects all namespaces. + // + // If PodSelector is also set, then the NetworkPolicyPeer as a whole selects + // the Pods matching PodSelector in the Namespaces selected by NamespaceSelector. + // Otherwise it selects all Pods in the Namespaces selected by NamespaceSelector. // +optional NamespaceSelector *metav1.LabelSelector `json:"namespaceSelector,omitempty" protobuf:"bytes,2,opt,name=namespaceSelector"` - // IPBlock defines policy on a particular IPBlock + // IPBlock defines policy on a particular IPBlock. If this field is set then + // neither of the other fields can be. // +optional IPBlock *IPBlock `json:"ipBlock,omitempty" protobuf:"bytes,3,rep,name=ipBlock"` } diff --git a/staging/src/k8s.io/api/networking/v1/types.go b/staging/src/k8s.io/api/networking/v1/types.go index 57bc8005e42..e1b81fdc7c4 100644 --- a/staging/src/k8s.io/api/networking/v1/types.go +++ b/staging/src/k8s.io/api/networking/v1/types.go @@ -161,22 +161,29 @@ type IPBlock struct { Except []string `json:"except,omitempty" protobuf:"bytes,2,rep,name=except"` } -// NetworkPolicyPeer describes a peer to allow traffic from. Exactly one of its fields -// must be specified. +// NetworkPolicyPeer describes a peer to allow traffic from. Only certain combinations of +// fields are allowed type NetworkPolicyPeer struct { - // This is a label selector which selects Pods in this namespace. This field - // follows standard label selector semantics. If present but empty, this selector - // selects all pods in this namespace. + // This is a label selector which selects Pods. This field follows standard label + // selector semantics; if present but empty, it selects all pods. + // + // If NamespaceSelector is also set, then the NetworkPolicyPeer as a whole selects + // the Pods matching PodSelector in the Namespaces selected by NamespaceSelector. + // Otherwise it selects the Pods matching PodSelector in the policy's own Namespace. // +optional PodSelector *metav1.LabelSelector `json:"podSelector,omitempty" protobuf:"bytes,1,opt,name=podSelector"` - // Selects Namespaces using cluster scoped-labels. This matches all pods in all - // namespaces selected by this label selector. This field follows standard label - // selector semantics. If present but empty, this selector selects all namespaces. + // Selects Namespaces using cluster-scoped labels. This field follows standard label + // selector semantics; if present but empty, it selects all namespaces. + // + // If PodSelector is also set, then the NetworkPolicyPeer as a whole selects + // the Pods matching PodSelector in the Namespaces selected by NamespaceSelector. + // Otherwise it selects all Pods in the Namespaces selected by NamespaceSelector. // +optional NamespaceSelector *metav1.LabelSelector `json:"namespaceSelector,omitempty" protobuf:"bytes,2,opt,name=namespaceSelector"` - // IPBlock defines policy on a particular IPBlock + // IPBlock defines policy on a particular IPBlock. If this field is set then + // neither of the other fields can be. // +optional IPBlock *IPBlock `json:"ipBlock,omitempty" protobuf:"bytes,3,rep,name=ipBlock"` }