update more kubectl bits for groupversion

This commit is contained in:
deads2k 2015-12-01 11:52:11 -05:00
parent 33eda2ffb5
commit 66eecb963a
20 changed files with 129 additions and 94 deletions

View File

@ -42,6 +42,12 @@ var (
IsRegistered = allGroups.IsRegistered IsRegistered = allGroups.IsRegistered
) )
// ExternalVersions is a list of all external versions for this API group in order of
// most preferred to least preferred
var ExternalVersions = []unversioned.GroupVersion{
{Group: "", Version: "v1"},
}
// GroupMetaMap is a map between group names and their metadata. // GroupMetaMap is a map between group names and their metadata.
type GroupMetaMap map[string]*GroupMeta type GroupMetaMap map[string]*GroupMeta

View File

@ -27,6 +27,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/version" "k8s.io/kubernetes/pkg/version"
) )
@ -183,12 +184,12 @@ func (c *Client) ValidateComponents() (*api.ComponentStatusList, error) {
// SwaggerSchemaInterface has a method to retrieve the swagger schema. Used in // SwaggerSchemaInterface has a method to retrieve the swagger schema. Used in
// client.Interface // client.Interface
type SwaggerSchemaInterface interface { type SwaggerSchemaInterface interface {
SwaggerSchema(groupVersion string) (*swagger.ApiDeclaration, error) SwaggerSchema(version unversioned.GroupVersion) (*swagger.ApiDeclaration, error)
} }
// SwaggerSchema retrieves and parses the swagger API schema the server supports. // SwaggerSchema retrieves and parses the swagger API schema the server supports.
func (c *Client) SwaggerSchema(groupVersion string) (*swagger.ApiDeclaration, error) { func (c *Client) SwaggerSchema(version unversioned.GroupVersion) (*swagger.ApiDeclaration, error) {
if groupVersion == "" { if version.IsEmpty() {
return nil, fmt.Errorf("groupVersion cannot be empty") return nil, fmt.Errorf("groupVersion cannot be empty")
} }
@ -198,14 +199,14 @@ func (c *Client) SwaggerSchema(groupVersion string) (*swagger.ApiDeclaration, er
} }
groupVersions := ExtractGroupVersions(groupList) groupVersions := ExtractGroupVersions(groupList)
// This check also takes care the case that kubectl is newer than the running endpoint // This check also takes care the case that kubectl is newer than the running endpoint
if stringDoesntExistIn(groupVersion, groupVersions) { if stringDoesntExistIn(version.String(), groupVersions) {
return nil, fmt.Errorf("API version: %s is not supported by the server. Use one of: %v", groupVersion, groupVersions) return nil, fmt.Errorf("API version: %v is not supported by the server. Use one of: %v", version, groupVersions)
} }
var path string var path string
if groupVersion == "v1" { if version == v1.SchemeGroupVersion {
path = "/swaggerapi/api/" + groupVersion path = "/swaggerapi/api/" + version.Version
} else { } else {
path = "/swaggerapi/apis/" + groupVersion path = "/swaggerapi/apis/" + version.Group + "/" + version.Version
} }
body, err := c.Get().AbsPath(path).Do().Raw() body, err := c.Get().AbsPath(path).Do().Raw()

View File

@ -31,6 +31,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
@ -496,7 +497,7 @@ func TestGetSwaggerSchema(t *testing.T) {
} }
client := NewOrDie(&Config{Host: server.URL}) client := NewOrDie(&Config{Host: server.URL})
got, err := client.SwaggerSchema("v1") got, err := client.SwaggerSchema(v1.SchemeGroupVersion)
if err != nil { if err != nil {
t.Fatalf("unexpected encoding error: %v", err) t.Fatalf("unexpected encoding error: %v", err)
} }
@ -506,7 +507,7 @@ func TestGetSwaggerSchema(t *testing.T) {
} }
func TestGetSwaggerSchemaFail(t *testing.T) { func TestGetSwaggerSchemaFail(t *testing.T) {
expErr := "API version: v4 is not supported by the server. Use one of: [v1 v2 v3]" expErr := "API version: api.group/v4 is not supported by the server. Use one of: [v1 v2 v3]"
server, err := swaggerSchemaFakeServer() server, err := swaggerSchemaFakeServer()
if err != nil { if err != nil {
@ -514,7 +515,7 @@ func TestGetSwaggerSchemaFail(t *testing.T) {
} }
client := NewOrDie(&Config{Host: server.URL}) client := NewOrDie(&Config{Host: server.URL})
got, err := client.SwaggerSchema("v4") got, err := client.SwaggerSchema(unversioned.GroupVersion{Group: "api.group", Version: "v4"})
if got != nil { if got != nil {
t.Fatalf("unexpected response: %v", got) t.Fatalf("unexpected response: %v", got)
} }

View File

@ -17,6 +17,7 @@ limitations under the License.
package latest package latest
import ( import (
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/v1" "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/v1"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
) )
@ -24,6 +25,8 @@ import (
// Version is the string that represents the current external default version. // Version is the string that represents the current external default version.
const Version = "v1" const Version = "v1"
var ExternalVersion = unversioned.GroupVersion{Group: "", Version: "v1"}
// OldestVersion is the string that represents the oldest server version supported, // OldestVersion is the string that represents the oldest server version supported,
// for client code that wants to hardcode the lowest common denominator. // for client code that wants to hardcode the lowest common denominator.
const OldestVersion = "v1" const OldestVersion = "v1"

View File

@ -25,6 +25,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/registered" "k8s.io/kubernetes/pkg/api/registered"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1"
client "k8s.io/kubernetes/pkg/client/unversioned" client "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/version" "k8s.io/kubernetes/pkg/version"
@ -306,10 +307,14 @@ func (c *Fake) ComponentStatuses() client.ComponentStatusInterface {
} }
// SwaggerSchema returns an empty swagger.ApiDeclaration for testing // SwaggerSchema returns an empty swagger.ApiDeclaration for testing
func (c *Fake) SwaggerSchema(version string) (*swagger.ApiDeclaration, error) { func (c *Fake) SwaggerSchema(version unversioned.GroupVersion) (*swagger.ApiDeclaration, error) {
action := ActionImpl{} action := ActionImpl{}
action.Verb = "get" action.Verb = "get"
action.Resource = "/swaggerapi/api/" + version if version == v1.SchemeGroupVersion {
action.Resource = "/swaggerapi/api/" + version.Version
} else {
action.Resource = "/swaggerapi/apis/" + version.Group + "/" + version.Version
}
c.Invokes(action, nil) c.Invokes(action, nil)
return &swagger.ApiDeclaration{}, nil return &swagger.ApiDeclaration{}, nil

View File

@ -95,7 +95,7 @@ func RunAutoscale(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []
} }
info := infos[0] info := infos[0]
mapping := info.ResourceMapping() mapping := info.ResourceMapping()
if err := f.CanBeAutoscaled(mapping.GroupVersionKind.Kind); err != nil { if err := f.CanBeAutoscaled(mapping.GroupVersionKind.GroupKind()); err != nil {
return err return err
} }

View File

@ -21,7 +21,6 @@ import (
"fmt" "fmt"
"io" "io"
"github.com/golang/glog"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd" "k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
@ -70,16 +69,12 @@ func NewCmdConfigView(out io.Writer, ConfigAccess ConfigAccess) *cobra.Command {
} }
printer, _, err := cmdutil.PrinterForCommand(cmd) printer, _, err := cmdutil.PrinterForCommand(cmd)
if err != nil { cmdutil.CheckErr(err)
glog.FatalDepth(1, err) version, err := cmdutil.OutputVersion(cmd, &latest.ExternalVersion)
} cmdutil.CheckErr(err)
version := cmdutil.OutputVersion(cmd, latest.Version)
printer = kubectl.NewVersionedPrinter(printer, clientcmdapi.Scheme, version) printer = kubectl.NewVersionedPrinter(printer, clientcmdapi.Scheme, version)
if err := options.Run(out, printer); err != nil { cmdutil.CheckErr(options.Run(out, printer))
glog.FatalDepth(1, err)
}
}, },
} }

View File

@ -90,17 +90,16 @@ type ConvertOptions struct {
out io.Writer out io.Writer
printer kubectl.ResourcePrinter printer kubectl.ResourcePrinter
outputVersion string outputVersion unversioned.GroupVersion
} }
// Complete collects information required to run Convert command from command line. // Complete collects information required to run Convert command from command line.
func (o *ConvertOptions) Complete(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) (err error) { func (o *ConvertOptions) Complete(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) (err error) {
o.outputVersion = cmdutil.OutputVersion(cmd, latest.GroupOrDie("").GroupVersion.Version) o.outputVersion, err = cmdutil.OutputVersion(cmd, &latest.ExternalVersions[0])
outputGV, err := unversioned.ParseGroupVersion(o.outputVersion)
if err != nil { if err != nil {
return fmt.Errorf("unable to parse group/version from %q: %v", o.outputVersion, err) return err
} }
if !registered.IsRegisteredAPIGroupVersion(outputGV) { if !registered.IsRegisteredAPIGroupVersion(o.outputVersion) {
cmdutil.UsageError(cmd, "'%s' is not a registered version.", o.outputVersion) cmdutil.UsageError(cmd, "'%s' is not a registered version.", o.outputVersion)
} }
@ -152,7 +151,7 @@ func (o *ConvertOptions) RunConvert() error {
return err return err
} }
objects, err := resource.AsVersionedObject(infos, false, o.outputVersion) objects, err := resource.AsVersionedObject(infos, false, o.outputVersion.String())
if err != nil { if err != nil {
return err return err
} }

View File

@ -28,6 +28,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/unversioned"
client "k8s.io/kubernetes/pkg/client/unversioned" client "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
@ -149,10 +150,13 @@ func RunEdit(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
windowsLineEndings := cmdutil.GetFlagBool(cmd, "windows-line-endings") windowsLineEndings := cmdutil.GetFlagBool(cmd, "windows-line-endings")
edit := editor.NewDefaultEditor(f.EditorEnvs()) edit := editor.NewDefaultEditor(f.EditorEnvs())
defaultVersion := cmdutil.OutputVersionFromGroupVersion(cmd, clientConfig.GroupVersion) defaultVersion, err := cmdutil.OutputVersion(cmd, clientConfig.GroupVersion)
if err != nil {
return err
}
results := editResults{} results := editResults{}
for { for {
objs, err := resource.AsVersionedObjects(infos, defaultVersion) objs, err := resource.AsVersionedObjects(infos, defaultVersion.String())
if err != nil { if err != nil {
return preservedFile(err, results.file, out) return preservedFile(err, results.file, out)
} }
@ -356,7 +360,7 @@ type editResults struct {
edit []*resource.Info edit []*resource.Info
file string file string
version string version unversioned.GroupVersion
} }
func (r *editResults) addError(err error, info *resource.Info) string { func (r *editResults) addError(err error, info *resource.Info) string {

View File

@ -22,6 +22,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/api/latest" "k8s.io/kubernetes/pkg/api/latest"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
) )
@ -70,7 +71,8 @@ func RunExplain(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []st
} }
recursive := cmdutil.GetFlagBool(cmd, "recursive") recursive := cmdutil.GetFlagBool(cmd, "recursive")
apiV := cmdutil.GetFlagString(cmd, "api-version") apiVersionString := cmdutil.GetFlagString(cmd, "api-version")
apiVersion := unversioned.GroupVersion{}
mapper, _ := f.Object() mapper, _ := f.Object()
// TODO: After we figured out the new syntax to separate group and resource, allow // TODO: After we figured out the new syntax to separate group and resource, allow
@ -87,14 +89,21 @@ func RunExplain(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []st
return err return err
} }
if len(apiV) == 0 { if len(apiVersionString) == 0 {
groupMeta, err := latest.Group(gvk.Group) groupMeta, err := latest.Group(gvk.Group)
if err != nil { if err != nil {
return err return err
} }
apiV = groupMeta.GroupVersion.String() apiVersion = groupMeta.GroupVersion
} else {
apiVersion, err = unversioned.ParseGroupVersion(apiVersionString)
if err != nil {
return nil
}
} }
swagSchema, err := kubectl.GetSwaggerSchema(apiV, client)
swagSchema, err := kubectl.GetSwaggerSchema(apiVersion, client)
if err != nil { if err != nil {
return err return err
} }

View File

@ -120,7 +120,7 @@ func RunExpose(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str
} }
info := infos[0] info := infos[0]
mapping := info.ResourceMapping() mapping := info.ResourceMapping()
if err := f.CanBeExposed(mapping.GroupVersionKind.Kind); err != nil { if err := f.CanBeExposed(mapping.GroupVersionKind.GroupKind()); err != nil {
return err return err
} }
// Get the input object // Get the input object

View File

@ -209,8 +209,11 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string
// the outermost object will be converted to the output-version, but inner // the outermost object will be converted to the output-version, but inner
// objects can use their mappings // objects can use their mappings
version := cmdutil.OutputVersionFromGroupVersion(cmd, clientConfig.GroupVersion) version, err := cmdutil.OutputVersion(cmd, clientConfig.GroupVersion)
obj, err := resource.AsVersionedObject(infos, !singular, version) if err != nil {
return err
}
obj, err := resource.AsVersionedObject(infos, !singular, version.String())
if err != nil { if err != nil {
return err return err
} }

View File

@ -164,7 +164,7 @@ func TestGetUnknownSchemaObjectListGeneric(t *testing.T) {
rcVersion: testapi.Default.Version(), rcVersion: testapi.Default.Version(),
}, },
"handles second specific version": { "handles second specific version": {
outputVersion: "unlikelyversion", outputVersion: "unlikely.group/unlikelyversion",
listVersion: testapi.Default.Version(), listVersion: testapi.Default.Version(),
testtypeVersion: unlikelyGV.String(), testtypeVersion: unlikelyGV.String(),
rcVersion: testapi.Default.Version(), // see expected behavior 3b rcVersion: testapi.Default.Version(), // see expected behavior 3b

View File

@ -95,9 +95,9 @@ type Factory struct {
// Returns the generator for the provided generator name // Returns the generator for the provided generator name
Generator func(name string) (kubectl.Generator, bool) Generator func(name string) (kubectl.Generator, bool)
// Check whether the kind of resources could be exposed // Check whether the kind of resources could be exposed
CanBeExposed func(kind string) error CanBeExposed func(kind unversioned.GroupKind) error
// Check whether the kind of resources could be autoscaled // Check whether the kind of resources could be autoscaled
CanBeAutoscaled func(kind string) error CanBeAutoscaled func(kind unversioned.GroupKind) error
// AttachablePodForObject returns the pod to which to attach given an object. // AttachablePodForObject returns the pod to which to attach given an object.
AttachablePodForObject func(object runtime.Object) (*api.Pod, error) AttachablePodForObject func(object runtime.Object) (*api.Pod, error)
// EditorEnvs returns a group of environment variables that the edit command // EditorEnvs returns a group of environment variables that the edit command
@ -140,12 +140,12 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
Object: func() (meta.RESTMapper, runtime.ObjectTyper) { Object: func() (meta.RESTMapper, runtime.ObjectTyper) {
cfg, err := clientConfig.ClientConfig() cfg, err := clientConfig.ClientConfig()
CheckErr(err) CheckErr(err)
cmdApiVersion := "" cmdApiVersion := unversioned.GroupVersion{}
if cfg.GroupVersion != nil { if cfg.GroupVersion != nil {
cmdApiVersion = cfg.GroupVersion.String() cmdApiVersion = *cfg.GroupVersion
} }
return kubectl.OutputVersionMapper{RESTMapper: mapper, OutputVersion: cmdApiVersion}, api.Scheme return kubectl.OutputVersionMapper{RESTMapper: mapper, OutputVersions: []unversioned.GroupVersion{cmdApiVersion}}, api.Scheme
}, },
Client: func() (*client.Client, error) { Client: func() (*client.Client, error) {
return clients.ClientForVersion("") return clients.ClientForVersion("")
@ -163,9 +163,9 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
return nil, err return nil, err
} }
switch gvk.Group { switch gvk.Group {
case "": case api.SchemeGroupVersion.Group:
return client.RESTClient, nil return client.RESTClient, nil
case "extensions": case extensions.SchemeGroupVersion.Group:
return client.ExtensionsClient.RESTClient, nil return client.ExtensionsClient.RESTClient, nil
} }
return nil, fmt.Errorf("unable to get RESTClient for resource '%s'", mapping.Resource) return nil, fmt.Errorf("unable to get RESTClient for resource '%s'", mapping.Resource)
@ -290,21 +290,21 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
generator, ok := generators[name] generator, ok := generators[name]
return generator, ok return generator, ok
}, },
CanBeExposed: func(kind string) error { CanBeExposed: func(kind unversioned.GroupKind) error {
switch kind { switch kind {
case "ReplicationController", "Service", "Pod": case api.Kind("ReplicationController"), api.Kind("Service"), api.Kind("Pod"):
// nothing to do here // nothing to do here
default: default:
return fmt.Errorf("cannot expose a %s", kind) return fmt.Errorf("cannot expose a %s", kind)
} }
return nil return nil
}, },
CanBeAutoscaled: func(kind string) error { CanBeAutoscaled: func(kind unversioned.GroupKind) error {
switch kind { switch kind {
case "ReplicationController", "Deployment": case api.Kind("ReplicationController"), extensions.Kind("Deployment"):
// nothing to do here // nothing to do here
default: default:
return fmt.Errorf("cannot autoscale a %s", kind) return fmt.Errorf("cannot autoscale a %v", kind)
} }
return nil return nil
}, },
@ -604,19 +604,20 @@ func (f *Factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMappin
if err != nil { if err != nil {
return nil, err return nil, err
} }
defaultVersion := ""
if clientConfig.GroupVersion != nil {
defaultVersion = clientConfig.GroupVersion.String()
}
version := OutputVersion(cmd, defaultVersion) version, err := OutputVersion(cmd, clientConfig.GroupVersion)
if len(version) == 0 { if err != nil {
version = mapping.GroupVersionKind.GroupVersion().String() return nil, err
} }
if len(version) == 0 { if version.IsEmpty() {
version = mapping.GroupVersionKind.GroupVersion()
}
if version.IsEmpty() {
return nil, fmt.Errorf("you must specify an output-version when using this output format") return nil, fmt.Errorf("you must specify an output-version when using this output format")
} }
printer = kubectl.NewVersionedPrinter(printer, mapping.ObjectConvertor, version, mapping.GroupVersionKind.GroupVersion().String())
printer = kubectl.NewVersionedPrinter(printer, mapping.ObjectConvertor, version, mapping.GroupVersionKind.GroupVersion())
} else { } else {
// Some callers do not have "label-columns" so we can't use the GetFlagStringSlice() helper // Some callers do not have "label-columns" so we can't use the GetFlagStringSlice() helper
columnLabel, err := cmd.Flags().GetStringSlice("label-columns") columnLabel, err := cmd.Flags().GetStringSlice("label-columns")
@ -629,6 +630,7 @@ func (f *Factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMappin
} }
printer = maybeWrapSortingPrinter(cmd, printer) printer = maybeWrapSortingPrinter(cmd, printer)
} }
return printer, nil return printer, nil
} }

View File

@ -170,15 +170,15 @@ func TestLabelsForObject(t *testing.T) {
func TestCanBeExposed(t *testing.T) { func TestCanBeExposed(t *testing.T) {
factory := NewFactory(nil) factory := NewFactory(nil)
tests := []struct { tests := []struct {
kind string kind unversioned.GroupKind
expectErr bool expectErr bool
}{ }{
{ {
kind: "ReplicationController", kind: api.Kind("ReplicationController"),
expectErr: false, expectErr: false,
}, },
{ {
kind: "Node", kind: api.Kind("Node"),
expectErr: true, expectErr: true,
}, },
} }

View File

@ -76,22 +76,18 @@ func ValidateOutputArgs(cmd *cobra.Command) error {
} }
// OutputVersion returns the preferred output version for generic content (JSON, YAML, or templates) // OutputVersion returns the preferred output version for generic content (JSON, YAML, or templates)
// TODO, when this has no callers, replace it with OutputVersionFromGroupVersion. Also this shoudl return a GroupVersion // defaultVersion is never mutated. Nil simply allows clean passing in common usage from client.Config
func OutputVersion(cmd *cobra.Command, defaultVersion string) string { func OutputVersion(cmd *cobra.Command, defaultVersion *unversioned.GroupVersion) (unversioned.GroupVersion, error) {
outputVersion := GetFlagString(cmd, "output-version") outputVersionString := GetFlagString(cmd, "output-version")
if len(outputVersion) == 0 { if len(outputVersionString) == 0 {
outputVersion = defaultVersion if defaultVersion == nil {
} return unversioned.GroupVersion{}, nil
return outputVersion }
}
// OutputVersionFromGroupVersion returns the preferred output version for generic content (JSON, YAML, or templates) return *defaultVersion, nil
func OutputVersionFromGroupVersion(cmd *cobra.Command, defaultGV *unversioned.GroupVersion) string {
outputVersion := GetFlagString(cmd, "output-version")
if len(outputVersion) == 0 && defaultGV != nil {
outputVersion = defaultGV.String()
} }
return outputVersion
return unversioned.ParseGroupVersion(outputVersionString)
} }
// PrinterForCommand returns the default printer for this command. // PrinterForCommand returns the default printer for this command.

View File

@ -24,6 +24,7 @@ import (
"github.com/emicklei/go-restful/swagger" "github.com/emicklei/go-restful/swagger"
"k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/unversioned"
apiutil "k8s.io/kubernetes/pkg/api/util" apiutil "k8s.io/kubernetes/pkg/api/util"
client "k8s.io/kubernetes/pkg/client/unversioned" client "k8s.io/kubernetes/pkg/client/unversioned"
) )
@ -32,8 +33,8 @@ var allModels = make(map[string]*swagger.NamedModel)
var recursive = false // this is global for convenience, can become int for multiple levels var recursive = false // this is global for convenience, can become int for multiple levels
// GetSwaggerSchema returns the swagger spec from master // GetSwaggerSchema returns the swagger spec from master
func GetSwaggerSchema(apiVer string, kubeClient client.Interface) (*swagger.ApiDeclaration, error) { func GetSwaggerSchema(version unversioned.GroupVersion, kubeClient client.Interface) (*swagger.ApiDeclaration, error) {
swaggerSchema, err := kubeClient.SwaggerSchema(apiVer) swaggerSchema, err := kubeClient.SwaggerSchema(version)
if err != nil { if err != nil {
return nil, fmt.Errorf("couldn't read swagger schema from server: %v", err) return nil, fmt.Errorf("couldn't read swagger schema from server: %v", err)
} }

View File

@ -47,14 +47,24 @@ func makeImageList(spec *api.PodSpec) string {
// correspond to a preferred output version (if feasible) // correspond to a preferred output version (if feasible)
type OutputVersionMapper struct { type OutputVersionMapper struct {
meta.RESTMapper meta.RESTMapper
OutputVersion string
// 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. // 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) { func (m OutputVersionMapper) RESTMapping(gk unversioned.GroupKind, versions ...string) (*meta.RESTMapping, error) {
mapping, err := m.RESTMapper.RESTMapping(gk, m.OutputVersion) for _, preferredVersion := range m.OutputVersions {
if err == nil { if gk.Group == preferredVersion.Group {
return mapping, nil mapping, err := m.RESTMapper.RESTMapping(gk, preferredVersion.Version)
if err == nil {
return mapping, nil
}
break
}
} }
return m.RESTMapper.RESTMapping(gk, versions...) return m.RESTMapper.RESTMapping(gk, versions...)

View File

@ -157,28 +157,28 @@ func (fn ResourcePrinterFunc) HandledResources() []string {
type VersionedPrinter struct { type VersionedPrinter struct {
printer ResourcePrinter printer ResourcePrinter
convertor runtime.ObjectConvertor convertor runtime.ObjectConvertor
version []string versions []unversioned.GroupVersion
} }
// NewVersionedPrinter wraps a printer to convert objects to a known API version prior to printing. // NewVersionedPrinter wraps a printer to convert objects to a known API version prior to printing.
func NewVersionedPrinter(printer ResourcePrinter, convertor runtime.ObjectConvertor, version ...string) ResourcePrinter { func NewVersionedPrinter(printer ResourcePrinter, convertor runtime.ObjectConvertor, versions ...unversioned.GroupVersion) ResourcePrinter {
return &VersionedPrinter{ return &VersionedPrinter{
printer: printer, printer: printer,
convertor: convertor, convertor: convertor,
version: version, versions: versions,
} }
} }
// PrintObj implements ResourcePrinter // PrintObj implements ResourcePrinter
func (p *VersionedPrinter) PrintObj(obj runtime.Object, w io.Writer) error { func (p *VersionedPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
if len(p.version) == 0 { if len(p.versions) == 0 {
return fmt.Errorf("no version specified, object cannot be converted") return fmt.Errorf("no version specified, object cannot be converted")
} }
for _, version := range p.version { for _, version := range p.versions {
if len(version) == 0 { if version.IsEmpty() {
continue continue
} }
converted, err := p.convertor.ConvertToVersion(obj, version) converted, err := p.convertor.ConvertToVersion(obj, version.String())
if conversion.IsNotRegisteredError(err) { if conversion.IsNotRegisteredError(err) {
continue continue
} }
@ -187,7 +187,7 @@ func (p *VersionedPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
} }
return p.printer.PrintObj(converted, w) return p.printer.PrintObj(converted, w)
} }
return fmt.Errorf("the object cannot be converted to any of the versions: %v", p.version) return fmt.Errorf("the object cannot be converted to any of the versions: %v", p.versions)
} }
// TODO: implement HandledResources() // TODO: implement HandledResources()

View File

@ -64,7 +64,7 @@ func TestVersionedPrinter(t *testing.T) {
return nil return nil
}), }),
api.Scheme, api.Scheme,
testapi.Default.Version(), *testapi.Default.GroupVersion(),
) )
if err := p.PrintObj(original, nil); err != nil { if err := p.PrintObj(original, nil); err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
@ -422,7 +422,7 @@ func TestTemplateStrings(t *testing.T) {
t.Fatalf("tmpl fail: %v", err) t.Fatalf("tmpl fail: %v", err)
} }
printer := NewVersionedPrinter(p, api.Scheme, testapi.Default.Version()) printer := NewVersionedPrinter(p, api.Scheme, *testapi.Default.GroupVersion())
for name, item := range table { for name, item := range table {
buffer := &bytes.Buffer{} buffer := &bytes.Buffer{}