Skip to content

Commit

Permalink
API Group Version changes
Browse files Browse the repository at this point in the history
Addresses comments on dc94f8d
Addresses comments on 4eba760
  • Loading branch information
soltysh authored and liggitt committed Jan 27, 2016
1 parent 943efce commit 03c2a2b
Show file tree
Hide file tree
Showing 64 changed files with 419 additions and 296 deletions.
6 changes: 3 additions & 3 deletions cmd/origin-version-change/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ var (
inputSource = flag.StringP("input", "i", "-", "Input source; '-' means stdin")
outputDest = flag.StringP("output", "o", "-", "Output destination; '-' means stdout")
rewrite = flag.StringP("rewrite", "r", "", "If nonempty, use this as both input and output.")
outputVersion = flag.StringP("out-version", "v", latest.Version, "Version to convert input to")
outputVersion = flag.StringP("out-version", "v", latest.Version.Version, "Version to convert input to")
)

// isYAML determines whether data is JSON or YAML formatted by seeing
Expand All @@ -47,12 +47,12 @@ func changeObjectsVersion(items []kruntime.Object) {
log.Fatalf("Unable to decode Template objects: %v", errs)
}
for i, obj := range items {
_, kind, err := api.Scheme.ObjectVersionAndKind(obj)
groupVersionKind, err := api.Scheme.ObjectKind(obj)
if err != nil {
glog.Infof("Template.Objects[%d]: Unable to determine version and kind: %v", i, err)
continue
}
mapping, err := latest.RESTMapper.RESTMapping(kind, *outputVersion)
mapping, err := latest.RESTMapper.RESTMapping(groupVersionKind.GroupKind(), *outputVersion)
if err != nil {
glog.Infof("Template.Objects[%d]: Unable to get REST mappings: %v", err)
continue
Expand Down
57 changes: 33 additions & 24 deletions pkg/api/latest/latest.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (

"k8s.io/kubernetes/pkg/api"
kmeta "k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/sets"

"github.com/golang/glog"

Expand All @@ -17,17 +17,17 @@ import (
)

// Version is the string that represents the current external default version.
const Version = "v1"
var Version = v1.SchemeGroupVersion

// OldestVersion is the string that represents the oldest server version supported,
// for client code that wants to hardcode the lowest common denominator.
const OldestVersion = "v1beta3"
var OldestVersion = v1beta3.SchemeGroupVersion

// Versions is the list of versions that are recognized in code. The order provided
// may be assumed to be least feature rich to most feature rich, and clients may
// choose to prefer the latter items in the list over the former items when presented
// may be assumed to be most preferred to least preferred, and clients may
// choose to prefer the earlier items in the list over the latter items when presented
// with a set of versions to choose.
var Versions = []string{"v1", "v1beta3"}
var Versions = []unversioned.GroupVersion{v1.SchemeGroupVersion, v1beta3.SchemeGroupVersion}

// Codec is the default codec for serializing output that should use
// the latest supported version. Use this Codec when writing to
Expand Down Expand Up @@ -55,27 +55,27 @@ var RESTMapper kmeta.RESTMapper

// InterfacesFor returns the default Codec and ResourceVersioner for a given version
// string, or an error if the version is not known.
func InterfacesFor(version string) (*kmeta.VersionInterfaces, error) {
func InterfacesFor(version unversioned.GroupVersion) (*kmeta.VersionInterfaces, error) {
switch version {
case "v1beta3":
case v1beta3.SchemeGroupVersion:
return &kmeta.VersionInterfaces{
Codec: v1beta3.Codec,
ObjectConvertor: api.Scheme,
MetadataAccessor: accessor,
}, nil
case "v1":
case v1.SchemeGroupVersion:
return &kmeta.VersionInterfaces{
Codec: v1.Codec,
ObjectConvertor: api.Scheme,
MetadataAccessor: accessor,
}, nil
default:
return nil, fmt.Errorf("unsupported storage version: %s (valid: %s)", version, strings.Join(Versions, ", "))
return nil, fmt.Errorf("unsupported storage version: %q (valid: %v)", version, Versions)
}
}

// originTypes are the hardcoded types defined by the OpenShift API.
var originTypes = sets.String{}
var originTypes = make(map[unversioned.GroupVersionKind]bool)

// UserResources are the resource names that apply to the primary, user facing resources used by
// client tools. They are in deletion-first order - dependent resources should be last.
Expand All @@ -87,23 +87,31 @@ var UserResources = []string{
"pods",
}

// OriginKind returns true if OpenShift owns the kind described in a given apiVersion.
func OriginKind(kind, apiVersion string) bool {
return originTypes.Has(kind)
// OriginKind returns true if OpenShift owns the GroupVersionKind.
func OriginKind(gvk unversioned.GroupVersionKind) bool {
return originTypes[gvk]
}

// IsKindInAnyOriginGroup returns true if OpenShift owns the kind described in any apiVersion.
// TODO: this may not work once we divide builds/deployments/images into their own API groups
func IsKindInAnyOriginGroup(kind string) bool {
for _, version := range Versions {
if OriginKind(version.WithKind(kind)) {
return true
}
}

return false
}

func init() {
// this keeps us consistent with old code. We can decide if we want to expand our RESTMapper to cover
// api.RESTMapper, which is different than what you'd get from latest.
kubeMapper := api.RESTMapper

// list of versions we support on the server, in preferred order
versions := []string{"v1", "v1beta3"}

originMapper := kmeta.NewDefaultRESTMapper(
"",
versions,
func(version string) (*kmeta.VersionInterfaces, error) {
Versions,
func(version unversioned.GroupVersion) (*kmeta.VersionInterfaces, error) {
interfaces, err := InterfacesFor(version)
if err != nil {
return nil, err
Expand Down Expand Up @@ -143,21 +151,22 @@ func init() {
}

// enumerate all supported versions, get the kinds, and register with the mapper how to address our resources
for _, version := range versions {
for _, version := range Versions {
for kind, t := range api.Scheme.KnownTypes(version) {
if !strings.Contains(t.PkgPath(), "openshift/origin") {
if _, ok := kindToRootScope[kind]; !ok {
continue
}
}
originTypes.Insert(kind)
scope := kmeta.RESTScopeNamespace
_, found := kindToRootScope[kind]
if found || (strings.HasSuffix(kind, "List") && kindToRootScope[strings.TrimSuffix(kind, "List")]) {
scope = kmeta.RESTScopeRoot
}
glog.V(6).Infof("Registering %s %s %s", kind, version, scope.Name())
originMapper.Add(scope, kind, version, false)
gvk := version.WithKind(kind)
originTypes[gvk] = true
glog.V(6).Infof("Registering %s %s", gvk.String(), scope.Name())
originMapper.Add(gvk, scope, false)
}
}

Expand Down
28 changes: 27 additions & 1 deletion pkg/api/latest/latest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package latest
import (
"testing"

kapi "k8s.io/kubernetes/pkg/api"
klatest "k8s.io/kubernetes/pkg/api/latest"
"k8s.io/kubernetes/pkg/api/meta"
)

func TestRESTRootScope(t *testing.T) {
for _, v := range [][]string{{"v1beta3"}, {"v1"}} {
mapping, err := RESTMapper.RESTMapping("Node", v...)
mapping, err := RESTMapper.RESTMapping(kapi.Kind("Node"), v...)
if err != nil {
t.Fatal(err)
}
Expand All @@ -17,3 +19,27 @@ func TestRESTRootScope(t *testing.T) {
}
}
}

func TestResourceToKind(t *testing.T) {
// Ensure we resolve to latest.Version
expectedGVK := Version.WithKind("User")
gvk, err := RESTMapper.KindFor("user")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if gvk != expectedGVK {
t.Fatalf("Expected RESTMapper.KindFor('user') to be %#v, got %#v", expectedGVK, gvk)
}
}

func TestUpstreamResourceToKind(t *testing.T) {
// Ensure we resolve to klatest.ExternalVersions[0]
expectedGVK := klatest.ExternalVersions[0].WithKind("Pod")
gvk, err := klatest.GroupOrDie(kapi.SchemeGroupVersion.Group).RESTMapper.KindFor("pod")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if gvk != expectedGVK {
t.Fatalf("Expected RESTMapper.KindFor('pod') to be %#v, got %#v", expectedGVK, gvk)
}
}
6 changes: 4 additions & 2 deletions pkg/api/latest/tags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import (
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/sets"

"github.com/openshift/origin/pkg/api"
)

func TestDescriptions(t *testing.T) {
for _, version := range Versions {
if version == "v1beta3" {
if version == OldestVersion {
// we don't care about descriptions here
continue
}
Expand Down Expand Up @@ -63,7 +65,7 @@ func checkDescriptions(objType reflect.Type, seen *map[reflect.Type]bool, t *tes
func TestInternalJsonTags(t *testing.T) {
seen := map[reflect.Type]bool{}

for _, apiType := range kapi.Scheme.KnownTypes("") {
for _, apiType := range kapi.Scheme.KnownTypes(api.SchemeGroupVersion) {
checkJsonTags(apiType, &seen, t)
}
}
Expand Down
5 changes: 5 additions & 0 deletions pkg/api/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package api
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"

_ "github.com/openshift/origin/pkg/authorization/api"
_ "github.com/openshift/origin/pkg/build/api"
Expand All @@ -19,6 +20,10 @@ import (
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = unversioned.GroupVersion{Group: "", Version: ""}

// Codec is the identity codec for this package - it can only convert itself
// to itself.
var Codec = runtime.CodecFor(api.Scheme, SchemeGroupVersion.String())

// Kind takes an unqualified kind and returns back a Group qualified GroupKind
func Kind(kind string) unversioned.GroupKind {
return SchemeGroupVersion.WithKind(kind).GroupKind()
Expand Down
36 changes: 18 additions & 18 deletions pkg/api/serialization_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"time"

"github.com/google/gofuzz"
"k8s.io/kubernetes/pkg/api"
kapi "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta"
apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/api/validation"
Expand Down Expand Up @@ -147,7 +147,7 @@ func fuzzInternalObject(t *testing.T, forVersion string, item runtime.Object, se
c.FuzzNoCustom(j)
if j.To == nil {
// To is defaulted to be not nil
j.To = &api.LocalObjectReference{}
j.To = &kapi.LocalObjectReference{}
}
},
func(j *image.ImageStreamImage, c fuzz.Continue) {
Expand Down Expand Up @@ -221,7 +221,7 @@ func fuzzInternalObject(t *testing.T, forVersion string, item runtime.Object, se
},
func(j *route.RouteSpec, c fuzz.Continue) {
c.FuzzNoCustom(j)
j.To = api.ObjectReference{
j.To = kapi.ObjectReference{
Kind: "Service",
Name: j.To.Name,
}
Expand Down Expand Up @@ -299,7 +299,7 @@ func fuzzInternalObject(t *testing.T, forVersion string, item runtime.Object, se
j.From.Kind = "DockerImage"
j.From.Name = specs[c.Intn(len(specs))]
},
func(j *api.PodSecurityContext, c fuzz.Continue) {
func(j *kapi.PodSecurityContext, c fuzz.Continue) {
c.FuzzNoCustom(j)
if forVersion == "v1beta3" {
// v1beta3 does not contain the PodSecurityContext type. For this API version, only fuzz
Expand All @@ -312,15 +312,15 @@ func fuzzInternalObject(t *testing.T, forVersion string, item runtime.Object, se
j.FSGroup = nil
}
},
func(j *api.GitRepoVolumeSource, c fuzz.Continue) {
func(j *kapi.GitRepoVolumeSource, c fuzz.Continue) {
c.FuzzNoCustom(j)
if forVersion == "v1beta3" {
// these fields are set to their empty state when testing v1beta3
// they were added to v1 after v1beta3 was disabled as a storage or API version, so we don't have to support v1beta3 round-tripping
j.Directory = ""
}
},
func(j *api.ISCSIVolumeSource, c fuzz.Continue) {
func(j *kapi.ISCSIVolumeSource, c fuzz.Continue) {
c.FuzzNoCustom(j)
if forVersion == "v1beta3" {
// these fields are set to their empty state when testing v1beta3
Expand All @@ -331,15 +331,15 @@ func fuzzInternalObject(t *testing.T, forVersion string, item runtime.Object, se
j.ISCSIInterface = "default"
}
},
func(j *api.Event, c fuzz.Continue) {
func(j *kapi.Event, c fuzz.Continue) {
c.FuzzNoCustom(j)
if forVersion == "v1beta3" {
// these fields are set to their empty state when testing v1beta3
// they were added to v1 after v1beta3 was disabled as a storage or API version, so we don't have to support v1beta3 round-tripping
j.Type = ""
}
},
func(j *api.Probe, c fuzz.Continue) {
func(j *kapi.Probe, c fuzz.Continue) {
c.FuzzNoCustom(j)
if forVersion == "v1beta3" {
// these fields are set to their empty state when testing v1beta3
Expand Down Expand Up @@ -381,7 +381,7 @@ func fuzzInternalObject(t *testing.T, forVersion string, item runtime.Object, se
func roundTrip(t *testing.T, codec runtime.Codec, originalItem runtime.Object) {
// Make a copy of the originalItem to give to conversion functions
// This lets us know if conversion messed with the input object
deepCopy, err := api.Scheme.DeepCopy(originalItem)
deepCopy, err := kapi.Scheme.DeepCopy(originalItem)
if err != nil {
t.Errorf("Could not copy object: %v", err)
return
Expand All @@ -406,13 +406,13 @@ func roundTrip(t *testing.T, codec runtime.Codec, originalItem runtime.Object) {
}
if reflect.TypeOf(item) != reflect.TypeOf(obj2) {
obj2conv := reflect.New(reflect.TypeOf(item).Elem()).Interface().(runtime.Object)
if err := api.Scheme.Convert(obj2, obj2conv); err != nil {
if err := kapi.Scheme.Convert(obj2, obj2conv); err != nil {
t.Errorf("0X: no conversion from %v to %v: %v", reflect.TypeOf(item), reflect.TypeOf(obj2), err)
return
}
obj2 = obj2conv
}
if !api.Semantic.DeepEqual(originalItem, obj2) {
if !kapi.Semantic.DeepEqual(originalItem, obj2) {
t.Errorf("1: %v: diff: %v\nCodec: %v\nData: %s\nSource: %s", name, util.ObjectDiff(originalItem, obj2), codec, string(data), util.ObjectGoPrintSideBySide(originalItem, obj2))
return
}
Expand All @@ -423,7 +423,7 @@ func roundTrip(t *testing.T, codec runtime.Codec, originalItem runtime.Object) {
t.Errorf("2: %v: %v", name, err)
return
}
if !api.Semantic.DeepEqual(originalItem, obj3) {
if !kapi.Semantic.DeepEqual(originalItem, obj3) {
t.Errorf("3: %v: diff: %v\nCodec: %v", name, util.ObjectDiff(originalItem, obj3), codec)
return
}
Expand All @@ -440,11 +440,11 @@ const fuzzIters = 20

// For debugging problems
func TestSpecificKind(t *testing.T) {
api.Scheme.Log(t)
defer api.Scheme.Log(nil)
kapi.Scheme.Log(t)
defer kapi.Scheme.Log(nil)

kind := "DeploymentConfig"
item, err := api.Scheme.New("", kind)
item, err := kapi.Scheme.New(osapi.SchemeGroupVersion.WithKind(kind))
if err != nil {
t.Errorf("Couldn't make a %v? %v", kind, err)
return
Expand All @@ -468,7 +468,7 @@ var nonInternalRoundTrippableTypes = sets.NewString("List", "ListOptions", "PodE

// TestTypes will try to roundtrip all OpenShift and Kubernetes stable api types
func TestTypes(t *testing.T) {
for kind, reflectType := range api.Scheme.KnownTypes("") {
for kind, reflectType := range kapi.Scheme.KnownTypes(osapi.SchemeGroupVersion) {
if !strings.Contains(reflectType.PkgPath(), "/origin/") && reflectType.PkgPath() != "k8s.io/kubernetes/pkg/api" {
continue
}
Expand All @@ -477,7 +477,7 @@ func TestTypes(t *testing.T) {
}
// Try a few times, since runTest uses random values.
for i := 0; i < fuzzIters; i++ {
item, err := api.Scheme.New("", kind)
item, err := kapi.Scheme.New(osapi.SchemeGroupVersion.WithKind(kind))
if err != nil {
t.Errorf("Couldn't make a %v? %v", kind, err)
continue
Expand All @@ -491,7 +491,7 @@ func TestTypes(t *testing.T) {
for _, v := range versions {
t.Logf("About to test %v with %q", kind, v)
fuzzInternalObject(t, v, item, seed)
roundTrip(t, runtime.CodecFor(api.Scheme, v), item)
roundTrip(t, runtime.CodecFor(kapi.Scheme, v), item)
}
continue
}
Expand Down
Loading

0 comments on commit 03c2a2b

Please sign in to comment.