Merge pull request #18024 from deads2k/gv-kubectl02

Auto commit by PR queue bot
This commit is contained in:
k8s-merge-robot 2015-12-07 11:47:40 -08:00
commit dc4bc2a566
20 changed files with 129 additions and 94 deletions

View File

@ -42,6 +42,12 @@ var (
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.
type GroupMetaMap map[string]*GroupMeta

View File

@ -27,6 +27,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1"
"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
// client.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.
func (c *Client) SwaggerSchema(groupVersion string) (*swagger.ApiDeclaration, error) {
if groupVersion == "" {
func (c *Client) SwaggerSchema(version unversioned.GroupVersion) (*swagger.ApiDeclaration, error) {
if version.IsEmpty() {
return nil, fmt.Errorf("groupVersion cannot be empty")
}
@ -198,14 +199,14 @@ func (c *Client) SwaggerSchema(groupVersion string) (*swagger.ApiDeclaration, er
}
groupVersions := ExtractGroupVersions(groupList)
// This check also takes care the case that kubectl is newer than the running endpoint
if stringDoesntExistIn(groupVersion, groupVersions) {
return nil, fmt.Errorf("API version: %s is not supported by the server. Use one of: %v", groupVersion, groupVersions)
if stringDoesntExistIn(version.String(), groupVersions) {
return nil, fmt.Errorf("API version: %v is not supported by the server. Use one of: %v", version, groupVersions)
}
var path string
if groupVersion == "v1" {
path = "/swaggerapi/api/" + groupVersion
if version == v1.SchemeGroupVersion {
path = "/swaggerapi/api/" + version.Version
} else {
path = "/swaggerapi/apis/" + groupVersion
path = "/swaggerapi/apis/" + version.Group + "/" + version.Version
}
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/testapi"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/runtime"
@ -496,7 +497,7 @@ func TestGetSwaggerSchema(t *testing.T) {
}
client := NewOrDie(&Config{Host: server.URL})
got, err := client.SwaggerSchema("v1")
got, err := client.SwaggerSchema(v1.SchemeGroupVersion)
if err != nil {
t.Fatalf("unexpected encoding error: %v", err)
}
@ -506,7 +507,7 @@ func TestGetSwaggerSchema(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()
if err != nil {
@ -514,7 +515,7 @@ func TestGetSwaggerSchemaFail(t *testing.T) {
}
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 {
t.Fatalf("unexpected response: %v", got)
}

View File

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

View File

@ -25,6 +25,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/registered"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1"
client "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/version"
@ -306,10 +307,14 @@ func (c *Fake) ComponentStatuses() client.ComponentStatusInterface {
}
// 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.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)
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]
mapping := info.ResourceMapping()
if err := f.CanBeAutoscaled(mapping.GroupVersionKind.Kind); err != nil {
if err := f.CanBeAutoscaled(mapping.GroupVersionKind.GroupKind()); err != nil {
return err
}

View File

@ -21,7 +21,6 @@ import (
"fmt"
"io"
"github.com/golang/glog"
"github.com/spf13/cobra"
"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)
if err != nil {
glog.FatalDepth(1, err)
}
version := cmdutil.OutputVersion(cmd, latest.Version)
cmdutil.CheckErr(err)
version, err := cmdutil.OutputVersion(cmd, &latest.ExternalVersion)
cmdutil.CheckErr(err)
printer = kubectl.NewVersionedPrinter(printer, clientcmdapi.Scheme, version)
if err := options.Run(out, printer); err != nil {
glog.FatalDepth(1, err)
}
cmdutil.CheckErr(options.Run(out, printer))
},
}

View File

@ -90,17 +90,16 @@ type ConvertOptions struct {
out io.Writer
printer kubectl.ResourcePrinter
outputVersion string
outputVersion unversioned.GroupVersion
}
// 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) {
o.outputVersion = cmdutil.OutputVersion(cmd, latest.GroupOrDie("").GroupVersion.Version)
outputGV, err := unversioned.ParseGroupVersion(o.outputVersion)
o.outputVersion, err = cmdutil.OutputVersion(cmd, &latest.ExternalVersions[0])
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)
}
@ -152,7 +151,7 @@ func (o *ConvertOptions) RunConvert() error {
return err
}
objects, err := resource.AsVersionedObject(infos, false, o.outputVersion)
objects, err := resource.AsVersionedObject(infos, false, o.outputVersion.String())
if err != nil {
return err
}

View File

@ -28,6 +28,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/unversioned"
client "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/kubectl"
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")
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{}
for {
objs, err := resource.AsVersionedObjects(infos, defaultVersion)
objs, err := resource.AsVersionedObjects(infos, defaultVersion.String())
if err != nil {
return preservedFile(err, results.file, out)
}
@ -356,7 +360,7 @@ type editResults struct {
edit []*resource.Info
file string
version string
version unversioned.GroupVersion
}
func (r *editResults) addError(err error, info *resource.Info) string {

View File

@ -22,6 +22,7 @@ import (
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/api/latest"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/kubectl"
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")
apiV := cmdutil.GetFlagString(cmd, "api-version")
apiVersionString := cmdutil.GetFlagString(cmd, "api-version")
apiVersion := unversioned.GroupVersion{}
mapper, _ := f.Object()
// 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
}
if len(apiV) == 0 {
if len(apiVersionString) == 0 {
groupMeta, err := latest.Group(gvk.Group)
if err != nil {
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 {
return err
}

View File

@ -120,7 +120,7 @@ func RunExpose(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str
}
info := infos[0]
mapping := info.ResourceMapping()
if err := f.CanBeExposed(mapping.GroupVersionKind.Kind); err != nil {
if err := f.CanBeExposed(mapping.GroupVersionKind.GroupKind()); err != nil {
return err
}
// 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
// objects can use their mappings
version := cmdutil.OutputVersionFromGroupVersion(cmd, clientConfig.GroupVersion)
obj, err := resource.AsVersionedObject(infos, !singular, version)
version, err := cmdutil.OutputVersion(cmd, clientConfig.GroupVersion)
if err != nil {
return err
}
obj, err := resource.AsVersionedObject(infos, !singular, version.String())
if err != nil {
return err
}

View File

@ -164,7 +164,7 @@ func TestGetUnknownSchemaObjectListGeneric(t *testing.T) {
rcVersion: testapi.Default.Version(),
},
"handles second specific version": {
outputVersion: "unlikelyversion",
outputVersion: "unlikely.group/unlikelyversion",
listVersion: testapi.Default.Version(),
testtypeVersion: unlikelyGV.String(),
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
Generator func(name string) (kubectl.Generator, bool)
// 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
CanBeAutoscaled func(kind string) error
CanBeAutoscaled func(kind unversioned.GroupKind) error
// AttachablePodForObject returns the pod to which to attach given an object.
AttachablePodForObject func(object runtime.Object) (*api.Pod, error)
// 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) {
cfg, err := clientConfig.ClientConfig()
CheckErr(err)
cmdApiVersion := ""
cmdApiVersion := unversioned.GroupVersion{}
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) {
return clients.ClientForVersion("")
@ -163,9 +163,9 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
return nil, err
}
switch gvk.Group {
case "":
case api.SchemeGroupVersion.Group:
return client.RESTClient, nil
case "extensions":
case extensions.SchemeGroupVersion.Group:
return client.ExtensionsClient.RESTClient, nil
}
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]
return generator, ok
},
CanBeExposed: func(kind string) error {
CanBeExposed: func(kind unversioned.GroupKind) error {
switch kind {
case "ReplicationController", "Service", "Pod":
case api.Kind("ReplicationController"), api.Kind("Service"), api.Kind("Pod"):
// nothing to do here
default:
return fmt.Errorf("cannot expose a %s", kind)
}
return nil
},
CanBeAutoscaled: func(kind string) error {
CanBeAutoscaled: func(kind unversioned.GroupKind) error {
switch kind {
case "ReplicationController", "Deployment":
case api.Kind("ReplicationController"), extensions.Kind("Deployment"):
// nothing to do here
default:
return fmt.Errorf("cannot autoscale a %s", kind)
return fmt.Errorf("cannot autoscale a %v", kind)
}
return nil
},
@ -604,19 +604,20 @@ func (f *Factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMappin
if err != nil {
return nil, err
}
defaultVersion := ""
if clientConfig.GroupVersion != nil {
defaultVersion = clientConfig.GroupVersion.String()
}
version := OutputVersion(cmd, defaultVersion)
if len(version) == 0 {
version = mapping.GroupVersionKind.GroupVersion().String()
version, err := OutputVersion(cmd, clientConfig.GroupVersion)
if err != nil {
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")
}
printer = kubectl.NewVersionedPrinter(printer, mapping.ObjectConvertor, version, mapping.GroupVersionKind.GroupVersion().String())
printer = kubectl.NewVersionedPrinter(printer, mapping.ObjectConvertor, version, mapping.GroupVersionKind.GroupVersion())
} else {
// Some callers do not have "label-columns" so we can't use the GetFlagStringSlice() helper
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)
}
return printer, nil
}

View File

@ -170,15 +170,15 @@ func TestLabelsForObject(t *testing.T) {
func TestCanBeExposed(t *testing.T) {
factory := NewFactory(nil)
tests := []struct {
kind string
kind unversioned.GroupKind
expectErr bool
}{
{
kind: "ReplicationController",
kind: api.Kind("ReplicationController"),
expectErr: false,
},
{
kind: "Node",
kind: api.Kind("Node"),
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)
// TODO, when this has no callers, replace it with OutputVersionFromGroupVersion. Also this shoudl return a GroupVersion
func OutputVersion(cmd *cobra.Command, defaultVersion string) string {
outputVersion := GetFlagString(cmd, "output-version")
if len(outputVersion) == 0 {
outputVersion = defaultVersion
}
return outputVersion
}
// defaultVersion is never mutated. Nil simply allows clean passing in common usage from client.Config
func OutputVersion(cmd *cobra.Command, defaultVersion *unversioned.GroupVersion) (unversioned.GroupVersion, error) {
outputVersionString := GetFlagString(cmd, "output-version")
if len(outputVersionString) == 0 {
if defaultVersion == nil {
return unversioned.GroupVersion{}, nil
}
// OutputVersionFromGroupVersion returns the preferred output version for generic content (JSON, YAML, or templates)
func OutputVersionFromGroupVersion(cmd *cobra.Command, defaultGV *unversioned.GroupVersion) string {
outputVersion := GetFlagString(cmd, "output-version")
if len(outputVersion) == 0 && defaultGV != nil {
outputVersion = defaultGV.String()
return *defaultVersion, nil
}
return outputVersion
return unversioned.ParseGroupVersion(outputVersionString)
}
// PrinterForCommand returns the default printer for this command.

View File

@ -24,6 +24,7 @@ import (
"github.com/emicklei/go-restful/swagger"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/unversioned"
apiutil "k8s.io/kubernetes/pkg/api/util"
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
// GetSwaggerSchema returns the swagger spec from master
func GetSwaggerSchema(apiVer string, kubeClient client.Interface) (*swagger.ApiDeclaration, error) {
swaggerSchema, err := kubeClient.SwaggerSchema(apiVer)
func GetSwaggerSchema(version unversioned.GroupVersion, kubeClient client.Interface) (*swagger.ApiDeclaration, error) {
swaggerSchema, err := kubeClient.SwaggerSchema(version)
if err != nil {
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)
type OutputVersionMapper struct {
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.
func (m OutputVersionMapper) RESTMapping(gk unversioned.GroupKind, versions ...string) (*meta.RESTMapping, error) {
mapping, err := m.RESTMapper.RESTMapping(gk, m.OutputVersion)
if err == nil {
return mapping, nil
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...)

View File

@ -157,28 +157,28 @@ func (fn ResourcePrinterFunc) HandledResources() []string {
type VersionedPrinter struct {
printer ResourcePrinter
convertor runtime.ObjectConvertor
version []string
versions []unversioned.GroupVersion
}
// 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{
printer: printer,
convertor: convertor,
version: version,
versions: versions,
}
}
// PrintObj implements ResourcePrinter
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")
}
for _, version := range p.version {
if len(version) == 0 {
for _, version := range p.versions {
if version.IsEmpty() {
continue
}
converted, err := p.convertor.ConvertToVersion(obj, version)
converted, err := p.convertor.ConvertToVersion(obj, version.String())
if conversion.IsNotRegisteredError(err) {
continue
}
@ -187,7 +187,7 @@ func (p *VersionedPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
}
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()

View File

@ -64,7 +64,7 @@ func TestVersionedPrinter(t *testing.T) {
return nil
}),
api.Scheme,
testapi.Default.Version(),
*testapi.Default.GroupVersion(),
)
if err := p.PrintObj(original, nil); err != nil {
t.Errorf("unexpected error: %v", err)
@ -422,7 +422,7 @@ func TestTemplateStrings(t *testing.T) {
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 {
buffer := &bytes.Buffer{}