diff --git a/pkg/printers/internalversion/BUILD b/pkg/printers/internalversion/BUILD index fa8d3bf6623..757909ffcb7 100644 --- a/pkg/printers/internalversion/BUILD +++ b/pkg/printers/internalversion/BUILD @@ -23,6 +23,7 @@ go_test( "//pkg/apis/autoscaling:go_default_library", "//pkg/apis/batch:go_default_library", "//pkg/apis/extensions:go_default_library", + "//pkg/apis/networking:go_default_library", "//pkg/apis/policy:go_default_library", "//pkg/apis/storage:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library", diff --git a/pkg/printers/internalversion/describe.go b/pkg/printers/internalversion/describe.go index 6e4cd463649..1de31478639 100644 --- a/pkg/printers/internalversion/describe.go +++ b/pkg/printers/internalversion/describe.go @@ -3096,13 +3096,63 @@ func describeNetworkPolicy(networkPolicy *networking.NetworkPolicy) (string, err w := NewPrefixWriter(out) w.Write(LEVEL_0, "Name:\t%s\n", networkPolicy.Name) w.Write(LEVEL_0, "Namespace:\t%s\n", networkPolicy.Namespace) + w.Write(LEVEL_0, "Created on:\t%s\n", networkPolicy.CreationTimestamp) printLabelsMultiline(w, "Labels", networkPolicy.Labels) printAnnotationsMultiline(w, "Annotations", networkPolicy.Annotations) - + describeNetworkPolicySpec(networkPolicy.Spec, w) return nil }) } +func describeNetworkPolicySpec(nps networking.NetworkPolicySpec, w PrefixWriter) { + w.Write(LEVEL_0, "Spec:\n") + w.Write(LEVEL_1, "Pod Selector: ") + if len(nps.PodSelector.MatchLabels) == 0 && len(nps.PodSelector.MatchExpressions) == 0 { + w.Write(LEVEL_2, " (Allowing the specific traffic to all pods in this namespace)\n") + } else { + w.Write(LEVEL_2, "%s\n", metav1.FormatLabelSelector(&nps.PodSelector)) + } + w.Write(LEVEL_1, "Allowing ingress traffic:\n") + printNetworkPolicySpecIngressFrom(nps.Ingress, " ", w) +} + +func printNetworkPolicySpecIngressFrom(npirs []networking.NetworkPolicyIngressRule, initialIndent string, w PrefixWriter) { + if len(npirs) == 0 { + w.WriteLine(" (Selected pods are isolated for ingress connectivity)") + return + } + for i, npir := range npirs { + if len(npir.Ports) == 0 { + w.Write(LEVEL_0, "%s%s\n", initialIndent, "To Port: (traffic allowed to all ports)") + } else { + for _, port := range npir.Ports { + var proto api.Protocol + if port.Protocol != nil { + proto = *port.Protocol + } else { + proto = api.ProtocolTCP + } + w.Write(LEVEL_0, "%s%s: %s/%s\n", initialIndent, "To Port", port.Port, proto) + } + } + if len(npir.From) == 0 { + w.Write(LEVEL_0, "%s%s\n", initialIndent, "From: (traffic not restricted by source)") + } else { + for _, from := range npir.From { + w.Write(LEVEL_0, "%s", initialIndent) + if from.PodSelector != nil { + w.Write(LEVEL_0, "%s: %s\n", "From Pod Selector", metav1.FormatLabelSelector(from.PodSelector)) + } else if from.NamespaceSelector != nil { + w.Write(LEVEL_0, "%s: %s\n", "From Namespace Selector", metav1.FormatLabelSelector(from.NamespaceSelector)) + } + } + } + if i != len(npirs)-1 { + w.Write(LEVEL_0, "%s%s\n", initialIndent, "----------") + } + } +} + type StorageClassDescriber struct { clientset.Interface } diff --git a/pkg/printers/internalversion/describe_test.go b/pkg/printers/internalversion/describe_test.go index b0cbda10350..e86dc6e9809 100644 --- a/pkg/printers/internalversion/describe_test.go +++ b/pkg/printers/internalversion/describe_test.go @@ -36,6 +36,7 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/apis/networking" "k8s.io/kubernetes/pkg/apis/policy" "k8s.io/kubernetes/pkg/apis/storage" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" @@ -1645,6 +1646,100 @@ func TestDescribeResourceQuota(t *testing.T) { } } +func TestDescribeNetworkPolicies(t *testing.T) { + expectedTime, err := time.Parse("2006-01-02 15:04:05 Z0700 MST", "2017-06-04 21:45:56 -0700 PDT") + if err != nil { + t.Errorf("unable to parse time %q error: %s", "2017-06-04 21:45:56 -0700 PDT", err) + } + expectedOut := `Name: network-policy-1 +Namespace: default +Created on: 2017-06-04 21:45:56 -0700 PDT +Labels: +Annotations: +Spec: + Pod Selector: foo in (bar1,bar2),foo2 notin (bar1,bar2),id1=app1,id2=app2 + Allowing ingress traffic: + To Port: 80/TCP + To Port: 82/TCP + From Pod Selector: id=app2,id2=app3 + From Namespace Selector: id=app2,id2=app3 + From Namespace Selector: foo in (bar1,bar2),id=app2,id2=app3 + ---------- + To Port: (traffic allowed to all ports) + From: (traffic not restricted by source) +` + + port80 := intstr.FromInt(80) + port82 := intstr.FromInt(82) + protoTCP := api.ProtocolTCP + + versionedFake := fake.NewSimpleClientset(&networking.NetworkPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "network-policy-1", + Namespace: "default", + CreationTimestamp: metav1.NewTime(expectedTime), + }, + Spec: networking.NetworkPolicySpec{ + PodSelector: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "id1": "app1", + "id2": "app2", + }, + MatchExpressions: []metav1.LabelSelectorRequirement{ + {Key: "foo", Operator: "In", Values: []string{"bar1", "bar2"}}, + {Key: "foo2", Operator: "NotIn", Values: []string{"bar1", "bar2"}}, + }, + }, + Ingress: []networking.NetworkPolicyIngressRule{ + { + Ports: []networking.NetworkPolicyPort{ + {Port: &port80}, + {Port: &port82, Protocol: &protoTCP}, + }, + From: []networking.NetworkPolicyPeer{ + { + PodSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "id": "app2", + "id2": "app3", + }, + }, + }, + { + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "id": "app2", + "id2": "app3", + }, + }, + }, + { + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "id": "app2", + "id2": "app3", + }, + MatchExpressions: []metav1.LabelSelectorRequirement{ + {Key: "foo", Operator: "In", Values: []string{"bar1", "bar2"}}, + }, + }, + }, + }, + }, + {}, + }, + }, + }) + d := NetworkPolicyDescriber{versionedFake} + out, err := d.Describe("", "network-policy-1", printers.DescriberSettings{}) + if err != nil { + t.Errorf("unexpected error: %s", err) + } + if out != expectedOut { + t.Errorf("want:\n%s\ngot:\n%s", expectedOut, out) + } +} + func TestDescribeServiceAccount(t *testing.T) { fake := fake.NewSimpleClientset(&api.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{