123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- /*
- Copyright 2014 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- // A set of common functions needed by cmd/kubectl and pkg/kubectl packages.
- package kubectl
- import (
- "errors"
- "fmt"
- "path"
- "strings"
- "k8s.io/kubernetes/pkg/api"
- "k8s.io/kubernetes/pkg/api/meta"
- "k8s.io/kubernetes/pkg/api/unversioned"
- )
- const (
- kubectlAnnotationPrefix = "kubectl.kubernetes.io/"
- )
- type NamespaceInfo struct {
- Namespace string
- }
- func listOfImages(spec *api.PodSpec) []string {
- images := make([]string, 0, len(spec.Containers))
- for _, container := range spec.Containers {
- images = append(images, container.Image)
- }
- return images
- }
- func makeImageList(spec *api.PodSpec) string {
- return strings.Join(listOfImages(spec), ",")
- }
- func NewThirdPartyResourceMapper(gvs []unversioned.GroupVersion, gvks []unversioned.GroupVersionKind) (meta.RESTMapper, error) {
- mapper := meta.NewDefaultRESTMapper(gvs, func(gv unversioned.GroupVersion) (*meta.VersionInterfaces, error) {
- for ix := range gvs {
- if gvs[ix].Group == gv.Group && gvs[ix].Version == gv.Version {
- return &meta.VersionInterfaces{
- ObjectConvertor: api.Scheme,
- MetadataAccessor: meta.NewAccessor(),
- }, nil
- }
- }
- groupVersions := make([]string, 0, len(gvs))
- for ix := range gvs {
- groupVersions = append(groupVersions, gvs[ix].String())
- }
- return nil, fmt.Errorf("unsupported storage version: %s (valid: %s)", gv.String(), strings.Join(groupVersions, ", "))
- })
- for ix := range gvks {
- mapper.Add(gvks[ix], meta.RESTScopeNamespace)
- }
- return mapper, nil
- }
- // OutputVersionMapper is a RESTMapper that will prefer mappings that
- // correspond to a preferred output version (if feasible)
- type OutputVersionMapper struct {
- meta.RESTMapper
- // output versions takes a list of preferred GroupVersions. Only the first
- // hit for a given group will have effect. This allows different output versions
- // depending upon the group of the kind being requested
- OutputVersions []unversioned.GroupVersion
- }
- // RESTMapping implements meta.RESTMapper by prepending the output version to the preferred version list.
- func (m OutputVersionMapper) RESTMapping(gk unversioned.GroupKind, versions ...string) (*meta.RESTMapping, error) {
- for _, preferredVersion := range m.OutputVersions {
- if gk.Group == preferredVersion.Group {
- mapping, err := m.RESTMapper.RESTMapping(gk, preferredVersion.Version)
- if err == nil {
- return mapping, nil
- }
- break
- }
- }
- return m.RESTMapper.RESTMapping(gk, versions...)
- }
- // ShortcutExpander is a RESTMapper that can be used for Kubernetes
- // resources. It expands the resource first, then invokes the wrapped RESTMapper
- type ShortcutExpander struct {
- RESTMapper meta.RESTMapper
- }
- var _ meta.RESTMapper = &ShortcutExpander{}
- func (e ShortcutExpander) KindFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionKind, error) {
- return e.RESTMapper.KindFor(expandResourceShortcut(resource))
- }
- func (e ShortcutExpander) KindsFor(resource unversioned.GroupVersionResource) ([]unversioned.GroupVersionKind, error) {
- return e.RESTMapper.KindsFor(expandResourceShortcut(resource))
- }
- func (e ShortcutExpander) ResourcesFor(resource unversioned.GroupVersionResource) ([]unversioned.GroupVersionResource, error) {
- return e.RESTMapper.ResourcesFor(expandResourceShortcut(resource))
- }
- func (e ShortcutExpander) ResourceFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionResource, error) {
- return e.RESTMapper.ResourceFor(expandResourceShortcut(resource))
- }
- func (e ShortcutExpander) RESTMapping(gk unversioned.GroupKind, versions ...string) (*meta.RESTMapping, error) {
- return e.RESTMapper.RESTMapping(gk, versions...)
- }
- func (e ShortcutExpander) RESTMappings(gk unversioned.GroupKind) ([]*meta.RESTMapping, error) {
- return e.RESTMapper.RESTMappings(gk)
- }
- func (e ShortcutExpander) ResourceSingularizer(resource string) (string, error) {
- return e.RESTMapper.ResourceSingularizer(expandResourceShortcut(unversioned.GroupVersionResource{Resource: resource}).Resource)
- }
- func (e ShortcutExpander) AliasesForResource(resource string) ([]string, bool) {
- return e.RESTMapper.AliasesForResource(expandResourceShortcut(unversioned.GroupVersionResource{Resource: resource}).Resource)
- }
- // shortForms is the list of short names to their expanded names
- var shortForms = map[string]string{
- // Please keep this alphabetized
- // If you add an entry here, please also take a look at pkg/kubectl/cmd/cmd.go
- // and add an entry to valid_resources when appropriate.
- "cm": "configmaps",
- "cs": "componentstatuses",
- "csr": "certificatesigningrequests",
- "deploy": "deployments",
- "ds": "daemonsets",
- "ep": "endpoints",
- "ev": "events",
- "hpa": "horizontalpodautoscalers",
- "ing": "ingresses",
- "limits": "limitranges",
- "no": "nodes",
- "ns": "namespaces",
- "po": "pods",
- "psp": "podSecurityPolicies",
- "pvc": "persistentvolumeclaims",
- "pv": "persistentvolumes",
- "quota": "resourcequotas",
- "rc": "replicationcontrollers",
- "rs": "replicasets",
- "sa": "serviceaccounts",
- "svc": "services",
- }
- // Look-up for resource short forms by value
- func ResourceShortFormFor(resource string) (string, bool) {
- var alias string
- exists := false
- for k, val := range shortForms {
- if val == resource {
- alias = k
- exists = true
- }
- }
- return alias, exists
- }
- // expandResourceShortcut will return the expanded version of resource
- // (something that a pkg/api/meta.RESTMapper can understand), if it is
- // indeed a shortcut. Otherwise, will return resource unmodified.
- func expandResourceShortcut(resource unversioned.GroupVersionResource) unversioned.GroupVersionResource {
- if expanded, ok := shortForms[resource.Resource]; ok {
- // don't change the group or version that's already been specified
- resource.Resource = expanded
- }
- return resource
- }
- // ResourceAliases returns the resource shortcuts and plural forms for the given resources.
- func ResourceAliases(rs []string) []string {
- as := make([]string, 0, len(rs))
- plurals := make(map[string]struct{}, len(rs))
- for _, r := range rs {
- var plural string
- switch {
- case r == "endpoints":
- plural = r // exception. "endpoint" does not exist. Why?
- case strings.HasSuffix(r, "y"):
- plural = r[0:len(r)-1] + "ies"
- case strings.HasSuffix(r, "s"):
- plural = r + "es"
- default:
- plural = r + "s"
- }
- as = append(as, plural)
- plurals[plural] = struct{}{}
- }
- for sf, r := range shortForms {
- if _, found := plurals[r]; found {
- as = append(as, sf)
- }
- }
- return as
- }
- // parseFileSource parses the source given. Acceptable formats include:
- //
- // 1. source-path: the basename will become the key name
- // 2. source-name=source-path: the source-name will become the key name and source-path is the path to the key file
- //
- // Key names cannot include '='.
- func parseFileSource(source string) (keyName, filePath string, err error) {
- numSeparators := strings.Count(source, "=")
- switch {
- case numSeparators == 0:
- return path.Base(source), source, nil
- case numSeparators == 1 && strings.HasPrefix(source, "="):
- return "", "", fmt.Errorf("key name for file path %v missing.", strings.TrimPrefix(source, "="))
- case numSeparators == 1 && strings.HasSuffix(source, "="):
- return "", "", fmt.Errorf("file path for key name %v missing.", strings.TrimSuffix(source, "="))
- case numSeparators > 1:
- return "", "", errors.New("Key names or file paths cannot contain '='.")
- default:
- components := strings.Split(source, "=")
- return components[0], components[1], nil
- }
- }
- // parseLiteralSource parses the source key=val pair
- func parseLiteralSource(source string) (keyName, value string, err error) {
- // leading equal is invalid
- if strings.Index(source, "=") == 0 {
- return "", "", fmt.Errorf("invalid literal source %v, expected key=value", source)
- }
- // split after the first equal (so values can have the = character)
- items := strings.SplitN(source, "=", 2)
- if len(items) != 2 {
- return "", "", fmt.Errorf("invalid literal source %v, expected key=value", source)
- }
- return items[0], items[1], nil
- }
|