diff --git a/Godeps/_workspace/src/k8s.io/kubernetes/pkg/kubectl/describe.go b/Godeps/_workspace/src/k8s.io/kubernetes/pkg/kubectl/describe.go index db10d8c7ffac..8e048a5982fb 100644 --- a/Godeps/_workspace/src/k8s.io/kubernetes/pkg/kubectl/describe.go +++ b/Godeps/_workspace/src/k8s.io/kubernetes/pkg/kubectl/describe.go @@ -23,6 +23,7 @@ import ( "io" "reflect" "sort" + "strconv" "strings" "time" @@ -93,6 +94,8 @@ func describerMap(c *client.Client) map[unversioned.GroupKind]Describer { extensions.Kind("Deployment"): &DeploymentDescriber{clientset.FromUnversionedClient(c)}, extensions.Kind("Job"): &JobDescriber{c}, extensions.Kind("Ingress"): &IngressDescriber{c}, + + api.Kind("SecurityContextConstraints"): &SecurityContextConstraintsDescriber{c}, } return m @@ -415,6 +418,117 @@ func describeQuota(resourceQuota *api.ResourceQuota) (string, error) { }) } +// SecurityContextConstraintsDescriber generates information about an SCC +type SecurityContextConstraintsDescriber struct { + client.Interface +} + +func (d *SecurityContextConstraintsDescriber) Describe(namespace, name string) (string, error) { + scc, err := d.SecurityContextConstraints().Get(name) + if err != nil { + return "", err + } + return describeSecurityContextConstraints(scc) +} + +func describeSecurityContextConstraints(scc *api.SecurityContextConstraints) (string, error) { + return tabbedString(func(out io.Writer) error { + fmt.Fprintf(out, "Name:\t%s\n", scc.Name) + + priority := "" + if scc.Priority != nil { + priority = strconv.Itoa(*scc.Priority) + } + fmt.Fprintf(out, "Priority:\t%s\n", stringOrNone(priority)) + + fmt.Fprintf(out, "Access:\t\n") + fmt.Fprintf(out, " Users:\t%s\n", stringOrNone(strings.Join(scc.Users, ","))) + fmt.Fprintf(out, " Groups:\t%s\n", stringOrNone(strings.Join(scc.Groups, ","))) + + fmt.Fprintf(out, "Settings:\t\n") + fmt.Fprintf(out, " Allow Privileged:\t%t\n", scc.AllowPrivilegedContainer) + fmt.Fprintf(out, " Default Add Capabilities:\t%s\n", capsToString(scc.DefaultAddCapabilities)) + fmt.Fprintf(out, " Required Drop Capabilities:\t%s\n", capsToString(scc.RequiredDropCapabilities)) + fmt.Fprintf(out, " Allowed Capabilities:\t%s\n", capsToString(scc.AllowedCapabilities)) + fmt.Fprintf(out, " Allow Host Dir Volumes:\t%t\n", scc.AllowHostDirVolumePlugin) + fmt.Fprintf(out, " Allow Host Network:\t%t\n", scc.AllowHostNetwork) + fmt.Fprintf(out, " Allow Host Ports:\t%t\n", scc.AllowHostPorts) + fmt.Fprintf(out, " Allow Host PID:\t%t\n", scc.AllowHostPID) + fmt.Fprintf(out, " Allow Host IPC:\t%t\n", scc.AllowHostIPC) + + fmt.Fprintf(out, " Run As User Strategy: %s\t\n", string(scc.RunAsUser.Type)) + uid := "" + if scc.RunAsUser.UID != nil { + uid = strconv.FormatInt(*scc.RunAsUser.UID, 10) + } + fmt.Fprintf(out, " UID:\t%s\n", stringOrNone(uid)) + + uidRangeMin := "" + if scc.RunAsUser.UIDRangeMin != nil { + uidRangeMin = strconv.FormatInt(*scc.RunAsUser.UIDRangeMin, 10) + } + fmt.Fprintf(out, " UID Range Min:\t%s\n", stringOrNone(uidRangeMin)) + + uidRangeMax := "" + if scc.RunAsUser.UIDRangeMax != nil { + uidRangeMax = strconv.FormatInt(*scc.RunAsUser.UIDRangeMax, 10) + } + fmt.Fprintf(out, " UID Range Max:\t%s\n", stringOrNone(uidRangeMax)) + + fmt.Fprintf(out, " SELinux Context Strategy: %s\t\n", string(scc.SELinuxContext.Type)) + var user, role, seLinuxType, level string + if scc.SELinuxContext.SELinuxOptions != nil { + user = scc.SELinuxContext.SELinuxOptions.User + role = scc.SELinuxContext.SELinuxOptions.Role + seLinuxType = scc.SELinuxContext.SELinuxOptions.Type + level = scc.SELinuxContext.SELinuxOptions.Level + } + fmt.Fprintf(out, " User:\t%s\n", stringOrNone(user)) + fmt.Fprintf(out, " Role:\t%s\n", stringOrNone(role)) + fmt.Fprintf(out, " Type:\t%s\n", stringOrNone(seLinuxType)) + fmt.Fprintf(out, " Level:\t%s\n", stringOrNone(level)) + + fmt.Fprintf(out, " FSGroup Strategy: %s\t\n", string(scc.FSGroup.Type)) + fmt.Fprintf(out, " Ranges:\t%s\n", idRangeToString(scc.FSGroup.Ranges)) + + fmt.Fprintf(out, " Supplemental Groups Strategy: %s\t\n", string(scc.SupplementalGroups.Type)) + fmt.Fprintf(out, " Ranges:\t%s\n", idRangeToString(scc.SupplementalGroups.Ranges)) + + return nil + }) +} + +func stringOrNone(s string) string { + if len(s) > 0 { + return s + } + return "" +} + +func idRangeToString(ranges []api.IDRange) string { + formattedString := "" + if ranges != nil { + strRanges := []string{} + for _, r := range ranges { + strRanges = append(strRanges, fmt.Sprintf("%d-%d", r.Min, r.Max)) + } + formattedString = strings.Join(strRanges, ",") + } + return stringOrNone(formattedString) +} + +func capsToString(caps []api.Capability) string { + formattedString := "" + if caps != nil { + strCaps := []string{} + for _, c := range caps { + strCaps = append(strCaps, string(c)) + } + formattedString = strings.Join(strCaps, ",") + } + return stringOrNone(formattedString) +} + // PodDescriber generates information about a pod and the replication controllers that // create it. type PodDescriber struct { diff --git a/Godeps/_workspace/src/k8s.io/kubernetes/pkg/kubectl/describe_test.go b/Godeps/_workspace/src/k8s.io/kubernetes/pkg/kubectl/describe_test.go index 43420fa144aa..0df1342df777 100644 --- a/Godeps/_workspace/src/k8s.io/kubernetes/pkg/kubectl/describe_test.go +++ b/Godeps/_workspace/src/k8s.io/kubernetes/pkg/kubectl/describe_test.go @@ -521,3 +521,20 @@ func TestDescribeDeployment(t *testing.T) { t.Errorf("unexpected out: %s", out) } } + +func TestDescribeSCC(t *testing.T) { + scc := &api.SecurityContextConstraints{ + ObjectMeta: api.ObjectMeta{ + Name: "bar", + }, + } + fake := testclient.NewSimpleFake(scc) + d := SecurityContextConstraintsDescriber{fake} + out, err := d.Describe(scc.Namespace, scc.Name) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if !strings.Contains(out, "bar") { + t.Errorf("unexpected out: %s", out) + } +} diff --git a/contrib/completions/bash/oc b/contrib/completions/bash/oc index f683259f9e0e..f9fcc1ef124a 100644 --- a/contrib/completions/bash/oc +++ b/contrib/completions/bash/oc @@ -1764,6 +1764,7 @@ _oc_describe() must_have_one_noun+=("rolebinding") must_have_one_noun+=("route") must_have_one_noun+=("secret") + must_have_one_noun+=("securitycontextconstraints") must_have_one_noun+=("service") must_have_one_noun+=("serviceaccount") must_have_one_noun+=("template") diff --git a/contrib/completions/bash/openshift b/contrib/completions/bash/openshift index 11bfa5b92fe3..64ebc9a36da7 100644 --- a/contrib/completions/bash/openshift +++ b/contrib/completions/bash/openshift @@ -7622,6 +7622,7 @@ _openshift_cli_describe() must_have_one_noun+=("rolebinding") must_have_one_noun+=("route") must_have_one_noun+=("secret") + must_have_one_noun+=("securitycontextconstraints") must_have_one_noun+=("service") must_have_one_noun+=("serviceaccount") must_have_one_noun+=("template") @@ -18636,6 +18637,7 @@ _openshift_kube_describe() must_have_one_noun+=("replicationcontroller") must_have_one_noun+=("resourcequota") must_have_one_noun+=("secret") + must_have_one_noun+=("securitycontextconstraints") must_have_one_noun+=("service") must_have_one_noun+=("serviceaccount") }