diff --git a/contrib/completions/bash/kubectl b/contrib/completions/bash/kubectl index e7380383f05..46b27db6e47 100644 --- a/contrib/completions/bash/kubectl +++ b/contrib/completions/bash/kubectl @@ -316,6 +316,7 @@ _kubectl_get() must_have_one_flag=() must_have_one_noun=() must_have_one_noun+=("componentstatus") + must_have_one_noun+=("configmap") must_have_one_noun+=("daemonset") must_have_one_noun+=("deployment") must_have_one_noun+=("endpoints") @@ -383,6 +384,7 @@ _kubectl_describe() must_have_one_flag=() must_have_one_noun=() + must_have_one_noun+=("configmap") must_have_one_noun+=("daemonset") must_have_one_noun+=("deployment") must_have_one_noun+=("endpoints") @@ -808,6 +810,7 @@ _kubectl_delete() must_have_one_flag=() must_have_one_noun=() must_have_one_noun+=("componentstatus") + must_have_one_noun+=("configmap") must_have_one_noun+=("daemonset") must_have_one_noun+=("deployment") must_have_one_noun+=("endpoints") @@ -1593,6 +1596,7 @@ _kubectl_label() must_have_one_flag=() must_have_one_noun=() must_have_one_noun+=("componentstatus") + must_have_one_noun+=("configmap") must_have_one_noun+=("daemonset") must_have_one_noun+=("deployment") must_have_one_noun+=("endpoints") diff --git a/docs/user-guide/configmap/config-map.yaml b/docs/user-guide/configmap/config-map.yaml new file mode 100644 index 00000000000..d14d725cfca --- /dev/null +++ b/docs/user-guide/configmap/config-map.yaml @@ -0,0 +1,7 @@ +apiVersion: extensions/v1beta1 +kind: ConfigMap +metadata: + name: test-configmap +data: + data-1: value-1 + data-2: value-2 diff --git a/hack/test-cmd.sh b/hack/test-cmd.sh index d90861e2c5a..3092589a6c7 100755 --- a/hack/test-cmd.sh +++ b/hack/test-cmd.sh @@ -1063,6 +1063,14 @@ __EOF__ kubectl delete deployment nginx-deployment "${kube_flags[@]}" kubectl delete rc -l deployment.kubernetes.io/podTemplateHash "${kube_flags[@]}" + ###################### + # ConfigMap # + ###################### + + kubectl create -f docs/user-guide/configmap/config-map.yaml + kube::test::get_object_assert configmap "{{range.items}}{{$id_field}}{{end}}" 'test-configmap' + kubectl delete configmap test-configmap "${kube_flags[@]}" + ###################### # Multiple Resources # ###################### diff --git a/pkg/kubectl/describe.go b/pkg/kubectl/describe.go index 4e6d6cd7075..99a2c1af669 100644 --- a/pkg/kubectl/describe.go +++ b/pkg/kubectl/describe.go @@ -90,6 +90,7 @@ func describerMap(c *client.Client) map[unversioned.GroupKind]Describer { extensions.Kind("Job"): &JobDescriber{c}, extensions.Kind("Deployment"): &DeploymentDescriber{c}, extensions.Kind("Ingress"): &IngressDescriber{c}, + extensions.Kind("ConfigMap"): &ConfigMapDescriber{c}, } return m @@ -1693,6 +1694,38 @@ func getPodStatusForController(c client.PodInterface, selector labels.Selector) return } +// ConfigMapDescriber generates information about a ConfigMap +type ConfigMapDescriber struct { + client.Interface +} + +func (d *ConfigMapDescriber) Describe(namespace, name string) (string, error) { + c := d.Extensions().ConfigMaps(namespace) + + configMap, err := c.Get(name) + if err != nil { + return "", err + } + + return describeConfigMap(configMap) +} + +func describeConfigMap(configMap *extensions.ConfigMap) (string, error) { + return tabbedString(func(out io.Writer) error { + fmt.Fprintf(out, "Name:\t%s\n", configMap.Name) + fmt.Fprintf(out, "Namespace:\t%s\n", configMap.Namespace) + fmt.Fprintf(out, "Labels:\t%s\n", labels.FormatLabels(configMap.Labels)) + fmt.Fprintf(out, "Annotations:\t%s\n", labels.FormatLabels(configMap.Annotations)) + + fmt.Fprintf(out, "\nData\n====\n") + for k, v := range configMap.Data { + fmt.Fprintf(out, "%s:\t%d bytes\n", k, len(v)) + } + + return nil + }) +} + // newErrNoDescriber creates a new ErrNoDescriber with the names of the provided types. func newErrNoDescriber(types ...reflect.Type) error { names := []string{} diff --git a/pkg/kubectl/resource_printer.go b/pkg/kubectl/resource_printer.go index d9e818e6b24..bd5a4266361 100644 --- a/pkg/kubectl/resource_printer.go +++ b/pkg/kubectl/resource_printer.go @@ -428,6 +428,7 @@ var thirdPartyResourceColumns = []string{"NAME", "DESCRIPTION", "VERSION(S)"} var horizontalPodAutoscalerColumns = []string{"NAME", "REFERENCE", "TARGET", "CURRENT", "MINPODS", "MAXPODS", "AGE"} var withNamespacePrefixColumns = []string{"NAMESPACE"} // TODO(erictune): print cluster name too. var deploymentColumns = []string{"NAME", "UPDATEDREPLICAS", "AGE"} +var configMapColumns = []string{"NAME", "DATA", "AGE"} // addDefaultHandlers adds print handlers for default Kubernetes types. func (h *HumanReadablePrinter) addDefaultHandlers() { @@ -473,6 +474,8 @@ func (h *HumanReadablePrinter) addDefaultHandlers() { h.Handler(deploymentColumns, printDeploymentList) h.Handler(horizontalPodAutoscalerColumns, printHorizontalPodAutoscaler) h.Handler(horizontalPodAutoscalerColumns, printHorizontalPodAutoscalerList) + h.Handler(configMapColumns, printConfigMap) + h.Handler(configMapColumns, printConfigMapList) } func (h *HumanReadablePrinter) unknown(data []byte, w io.Writer) error { @@ -1461,6 +1464,31 @@ func printHorizontalPodAutoscalerList(list *extensions.HorizontalPodAutoscalerLi return nil } +func printConfigMap(configMap *extensions.ConfigMap, w io.Writer, options printOptions) error { + name := configMap.Name + namespace := configMap.Namespace + + if options.withNamespace { + if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil { + return err + } + } + if _, err := fmt.Fprintf(w, "%s\t%v\t%s", name, len(configMap.Data), translateTimestamp(configMap.CreationTimestamp)); err != nil { + return err + } + _, err := fmt.Fprint(w, appendLabels(configMap.Labels, options.columnLabels)) + return err +} + +func printConfigMapList(list *extensions.ConfigMapList, w io.Writer, options printOptions) error { + for i := range list.Items { + if err := printConfigMap(&list.Items[i], w, options); err != nil { + return err + } + } + return nil +} + func appendLabels(itemLabels map[string]string, columnLabels []string) string { var buffer bytes.Buffer diff --git a/pkg/master/master.go b/pkg/master/master.go index 4a767fa1d44..1c17cf5cb20 100644 --- a/pkg/master/master.go +++ b/pkg/master/master.go @@ -37,6 +37,7 @@ import ( kubeletclient "k8s.io/kubernetes/pkg/kubelet/client" "k8s.io/kubernetes/pkg/master/ports" "k8s.io/kubernetes/pkg/registry/componentstatus" + configmapetcd "k8s.io/kubernetes/pkg/registry/configmap/etcd" controlleretcd "k8s.io/kubernetes/pkg/registry/controller/etcd" deploymentetcd "k8s.io/kubernetes/pkg/registry/deployment/etcd" "k8s.io/kubernetes/pkg/registry/endpoint" @@ -557,7 +558,7 @@ func (m *Master) thirdpartyapi(group, kind, version string) *apiserver.APIGroupV // getExperimentalResources returns the resources for extenstions api func (m *Master) getExtensionResources(c *Config) map[string]rest.Storage { // All resources except these are disabled by default. - enabledResources := sets.NewString("jobs", "horizontalpodautoscalers", "ingresses") + enabledResources := sets.NewString("jobs", "horizontalpodautoscalers", "ingresses", "configmaps") resourceOverrides := m.ApiGroupVersionOverrides["extensions/v1beta1"].ResourceOverrides isEnabled := func(resource string) bool { // Check if the resource has been overriden. @@ -619,6 +620,10 @@ func (m *Master) getExtensionResources(c *Config) map[string]rest.Storage { storage["ingresses"] = ingressStorage storage["ingresses/status"] = ingressStatusStorage } + if isEnabled("configmaps") { + storage["configmaps"] = configmapetcd.NewREST(dbClient("configmaps"), storageDecorator) + } + return storage }