Skip to content

Commit

Permalink
Merge pull request #211 from pwittrock/dep
Browse files Browse the repository at this point in the history
Override GetAttrs and TriggerFunc example
  • Loading branch information
Phillip Wittrock committed Jan 22, 2018
2 parents e68b327 + 4cc8c64 commit 064645b
Show file tree
Hide file tree
Showing 10 changed files with 203 additions and 22 deletions.
28 changes: 14 additions & 14 deletions cmd/apiregister-gen/generators/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -704,13 +704,13 @@ func (apigroup *APIGroup) DoType(t *types.Type) (*Struct, []*types.Type) {

uType = prefix + uImportName + "." + name

fmt.Printf("\nDifferent Parent Package: %s\nChild Package: %s\nKind: %s (Kind.String() %s)\nImport stmt: %s\nType: %s\n\n",
pkg,
member.Type.Name.Package,
member.Type.Kind,
member.Type.String(),
uImport,
uType)
//fmt.Printf("\nDifferent Parent Package: %s\nChild Package: %s\nKind: %s (Kind.String() %s)\nImport stmt: %s\nType: %s\n\n",
// pkg,
// member.Type.Name.Package,
// member.Type.Kind,
// member.Type.String(),
// uImport,
// uType)
} else {
// Handle non- Pointer, Maps, Slices
pkg := t.Name.Package
Expand All @@ -727,13 +727,13 @@ func (apigroup *APIGroup) DoType(t *types.Type) (*Struct, []*types.Type) {
// Create the field type name - should be <pkgalias>.<TypeName>
uType = uImportName + "." + name

fmt.Printf("\nDifferent Parent Package: %s\nChild Package: %s\nKind: %s (Kind.String() %s)\nImport stmt: %s\nType: %s\n\n",
pkg,
member.Type.Name.Package,
member.Type.Kind,
member.Type.String(),
uImport,
uType)
//fmt.Printf("\nDifferent Parent Package: %s\nChild Package: %s\nKind: %s (Kind.String() %s)\nImport stmt: %s\nType: %s\n\n",
// pkg,
// member.Type.Name.Package,
// member.Type.Kind,
// member.Type.String(),
// uImport,
// uType)
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion cmd/apiregister-gen/generators/unversioned_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,17 +74,19 @@ var (
{{ range $api := .UnversionedResources -}}
Internal{{ $api.Kind }} = builders.NewInternalResource(
"{{ $api.Resource }}",
"{{ $api.Kind }}",
func() runtime.Object { return &{{ $api.Kind }}{} },
func() runtime.Object { return &{{ $api.Kind }}List{} },
)
Internal{{ $api.Kind }}Status = builders.NewInternalResourceStatus(
"{{ $api.Resource }}",
"{{ $api.Kind }}Status",
func() runtime.Object { return &{{ $api.Kind }}{} },
func() runtime.Object { return &{{ $api.Kind }}List{} },
)
{{ range $subresource := .Subresources -}}
Internal{{$subresource.REST}} = builders.NewInternalSubresource(
"{{$subresource.Resource}}", "{{$subresource.Path}}",
"{{$subresource.Resource}}", "{{$subresource.Request}}", "{{$subresource.Path}}",
func() runtime.Object { return &{{$subresource.Request}}{} },
)
{{ end -}}
Expand Down
47 changes: 47 additions & 0 deletions example/pkg/apis/innsmouth/v1/deepone_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,51 @@ var _ = Describe("Deepone", func() {
})
})
})

Describe("when listing a resource", func() {
Context("using labels", func() {
It("should find the matchings objects", func() {
instance1 := DeepOne{}
instance1.Name = "deepone-1"
instance1.Spec.FishRequired = 150
instance1.Labels = map[string]string{"foo": "1"}

expected1 := instance1

instance2 := DeepOne{}
instance2.Name = "deepone-2"
instance2.Spec.FishRequired = 140
instance2.Labels = map[string]string{"foo": "2"}

expected2 := instance2

client = cs.InnsmouthV1().DeepOnes("deepone-test-valid")

By("returning success from the create request")
_, err := client.Create(&instance1)
Expect(err).ShouldNot(HaveOccurred())

By("returning success from the create request")
_, err = client.Create(&instance2)
Expect(err).ShouldNot(HaveOccurred())

By("returning the item for list requests")
result, err := client.List(metav1.ListOptions{LabelSelector: "foo=1"})
Expect(err).ShouldNot(HaveOccurred())
Expect(result.Items).To(HaveLen(1))
Expect(result.Items[0].Spec).To(Equal(expected1.Spec))

By("returning the item for list requests")
result, err = client.List(metav1.ListOptions{LabelSelector: "foo=2"})
Expect(err).ShouldNot(HaveOccurred())
Expect(result.Items).To(HaveLen(1))
Expect(result.Items[0].Spec).To(Equal(expected2.Spec))

By("returning the item for list requests")
result, err = client.List(metav1.ListOptions{})
Expect(err).ShouldNot(HaveOccurred())
Expect(result.Items).To(HaveLen(2))
})
})
})
})
46 changes: 46 additions & 0 deletions example/pkg/apis/olympus/v1beta1/poseidon_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package v1beta1

import (
"fmt"
"log"

"k8s.io/api/core/v1"
Expand All @@ -28,6 +29,10 @@ import (

"github.com/kubernetes-incubator/apiserver-builder/example/pkg/apis/olympus"
"k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/storage"
)

// +genclient
Expand Down Expand Up @@ -69,3 +74,44 @@ func (PoseidonSchemeFns) DefaultingFunction(o interface{}) {
// set default field values here
log.Printf("Defaulting fields for Poseidon %s\n", obj.Name)
}

func (b PoseidonStrategy) TriggerFunc(obj runtime.Object) []storage.MatchValue {
// Change this function to override the trigger fn that is used
value := b.DefaultStorageStrategy.TriggerFunc(obj)
return value
}

// The following functions allow spec.deployment.name to be selected when listing
// or watching resources
func (b PoseidonStrategy) GetAttrs(o runtime.Object) (labels.Set, fields.Set, bool, error) {
// Change this function to override the attributes that are matched
l, _, uninit, e := b.DefaultStorageStrategy.GetAttrs(o)
obj := o.(*olympus.Poseidon)

fs := fields.Set{"spec.deployment.name": obj.Spec.Deployment.Name}
fs = generic.AddObjectMetaFieldsSet(fs, &obj.ObjectMeta, true)
return l, fs, uninit, e
}

func (b PoseidonStrategy) BasicMatch(label labels.Selector, field fields.Selector) storage.SelectionPredicate {
return storage.SelectionPredicate{
Label: label,
Field: field,
GetAttrs: b.GetAttrs,
IndexFields: []string{"spec.deployment.name"},
}
}

// All field selector fields must appear in this function
func (b PoseidonSchemeFns) FieldSelectorConversion(label, value string) (string, string, error) {
switch label {
case "metadata.name":
return label, value, nil
case "metadata.namespace":
return label, value, nil
case "spec.deployment.name":
return label, value, nil
default:
return "", "", fmt.Errorf("%q is not a known field selector: only %q, %q, %q", label, "metadata.name", "metadata.namespace", "spec.deployment.name")
}
}
45 changes: 45 additions & 0 deletions example/pkg/apis/olympus/v1beta1/poseidon_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,49 @@ var _ = Describe("Poseidon", func() {
})
})
})

Describe("when listing a resource", func() {
Context("using labels", func() {
It("shouldn't find the matchings objects because the functions are overriden", func() {
client = cs.OlympusV1beta1().Poseidons("poseidon-test-valid")

instance1 := Poseidon{}
instance1.Name = "instance-1"
instance1.Spec.Deployment.Name = "i1"
instance1.Labels = map[string]string{"foo": "1"}
expected1 := instance1

instance2 := Poseidon{}
instance2.Name = "instance-2"
instance2.Spec.Deployment.Name = "i2"
instance2.Labels = map[string]string{"foo": "2"}
expected2 := instance2

By("returning success from the create request")
_, err := client.Create(&instance1)
Expect(err).ShouldNot(HaveOccurred())

By("returning success from the create request")
_, err = client.Create(&instance2)
Expect(err).ShouldNot(HaveOccurred())

By("returning the item for list requests")
result, err := client.List(metav1.ListOptions{FieldSelector: "spec.deployment.name=i1"})
Expect(err).ShouldNot(HaveOccurred())
Expect(result.Items).To(HaveLen(1))
Expect(result.Items[0].Name).To(Equal(expected1.Name))

By("returning the item for list requests")
result, err = client.List(metav1.ListOptions{FieldSelector: "spec.deployment.name=i2"})
Expect(err).ShouldNot(HaveOccurred())
Expect(result.Items).To(HaveLen(1))
Expect(result.Items[0].Name).To(Equal(expected2.Name))

By("returning the item for list requests")
result, err = client.List(metav1.ListOptions{})
Expect(err).ShouldNot(HaveOccurred())
Expect(result.Items).To(HaveLen(2))
})
})
})
})
19 changes: 14 additions & 5 deletions pkg/builders/api_unversioned_resource_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,18 @@ import (
// name - name of the resource - e.g. "deployments"
// new - function for creating new empty UNVERSIONED instances - e.g. func() runtime.Object { return &Deployment{} }
// newList - function for creating an empty list of UNVERSIONED instances - e.g. func() runtime.Object { return &DeploymentList{} }
func NewInternalResource(name string, new, newList func() runtime.Object) UnversionedResourceBuilder {
return NewBuilder(name, "", new, newList, true)
func NewInternalResource(name, kind string, new, newList func() runtime.Object) UnversionedResourceBuilder {
return NewBuilder(name, kind, "", new, newList, true)
}

// NewInternalResourceStatus returns a new strategy for the status subresource of an object
// name - name of the resource - e.g. "deployments"
// new - function for creating new empty UNVERSIONED instances - e.g. func() runtime.Object { return &Deployment{} }
// newList - function for creating an empty list of UNVERSIONED instances - e.g. func() runtime.Object { return &DeploymentList{} }
func NewInternalResourceStatus(name string, new, newList func() runtime.Object) UnversionedResourceBuilder {
func NewInternalResourceStatus(name, kind string, new, newList func() runtime.Object) UnversionedResourceBuilder {
return NewBuilder(
name,
kind,
"status",
new, newList,
true)
Expand All @@ -44,9 +45,10 @@ func NewInternalResourceStatus(name string, new, newList func() runtime.Object)
// name - name of the resource - e.g. "deployments"
// path - path to the subresource - e.g. "scale"
// new - function for creating new empty UNVERSIONED instances - e.g. func() runtime.Object { return &Deployment{} }
func NewInternalSubresource(name, path string, new func() runtime.Object) UnversionedResourceBuilder {
func NewInternalSubresource(name, kind, path string, new func() runtime.Object) UnversionedResourceBuilder {
return NewBuilder(
name,
kind,
path,
new,
nil, // Don't provide a list function
Expand All @@ -55,13 +57,14 @@ func NewInternalSubresource(name, path string, new func() runtime.Object) Unvers
}

func NewBuilder(
name, path string,
name, kind, path string,
new, newList func() runtime.Object,
useRegistryStore bool) UnversionedResourceBuilder {

return &UnversionedResourceBuilderImpl{
path,
name,
kind,
new,
newList,
useRegistryStore,
Expand All @@ -78,12 +81,14 @@ type UnversionedResourceBuilder interface {

GetPath() string
GetName() string
GetKind() string
ShouldUseRegistryStore() bool
}

type UnversionedResourceBuilderImpl struct {
Path string
Name string
Kind string
NewFunc func() runtime.Object
NewListFunc func() runtime.Object
UseRegistryStore bool
Expand All @@ -97,6 +102,10 @@ func (b *UnversionedResourceBuilderImpl) GetName() string {
return b.Name
}

func (b *UnversionedResourceBuilderImpl) GetKind() string {
return b.Kind
}

func (b *UnversionedResourceBuilderImpl) ShouldUseRegistryStore() bool {
return b.UseRegistryStore
}
Expand Down
20 changes: 19 additions & 1 deletion pkg/builders/api_version_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ func NewApiVersion(group, version string) *VersionedApiBuilder {
b := &VersionedApiBuilder{
GroupVersion: schema.GroupVersion{group, version},
}
b.SchemaBuilder = runtime.NewSchemeBuilder(b.registerTypes, b.registerDefaults, b.registerConversions)
b.SchemaBuilder = runtime.NewSchemeBuilder(
b.registerTypes,
b.registerDefaults,
b.registerConversions,
b.registerSelectorConversions)
return b
}

Expand Down Expand Up @@ -92,6 +96,20 @@ func (s *VersionedApiBuilder) registerConversions(scheme *runtime.Scheme) error
return nil
}

func (s *VersionedApiBuilder) registerSelectorConversions(scheme *runtime.Scheme) error {
for _, k := range s.Kinds {
err := scheme.AddFieldLabelConversionFunc(
s.GroupVersion.String(),
k.Unversioned.GetKind(),
k.SchemeFns.FieldSelectorConversion)
if err != nil {
glog.Errorf("Failed to add conversion functions %v", err)
return err
}
}
return nil
}

// registerEndpoints registers the REST endpoints for all resources in this API group version
// group is the group to register the resources under
// optionsGetter is the RESTOptionsGetter provided by a server.Config
Expand Down
4 changes: 4 additions & 0 deletions pkg/builders/default_scheme_fns.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,7 @@ func (DefaultSchemeFns) DefaultingFunction(interface{}) {}
func (DefaultSchemeFns) GetConversionFunctions() []interface{} { return []interface{}{} }

func (DefaultSchemeFns) Register(scheme *runtime.Scheme) error { return nil }

func (DefaultSchemeFns) FieldSelectorConversion(label, value string) (string, string, error) {
return runtime.DefaultMetaV1FieldSelectorConversion(label, value)
}
10 changes: 9 additions & 1 deletion pkg/builders/default_storage_strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ func (DefaultStorageStrategy) Build(builder StorageBuilder, store *StorageWrappe
store.DeleteStrategy = builder

options.AttrFunc = builder.GetAttrs
options.TriggerFunc = builder.TriggerFunc
}

func (DefaultStorageStrategy) NamespaceScoped() bool { return true }
Expand Down Expand Up @@ -114,13 +115,20 @@ func (b DefaultStorageStrategy) GetAttrs(obj runtime.Object) (labels.Set, fields
switch t := obj.(type) {
case HasObjectMeta:
apiserver := obj.(HasObjectMeta)
return labels.Set(apiserver.GetObjectMeta().Labels), b.GetSelectableFields(apiserver), false, nil
return labels.Set(apiserver.GetObjectMeta().Labels),
b.GetSelectableFields(apiserver),
apiserver.GetObjectMeta().Initializers != nil,
nil
default:
return nil, nil, false, fmt.Errorf(
"Cannot get attributes for object type %v which does not implement HasObjectMeta.", t)
}
}

func (b DefaultStorageStrategy) TriggerFunc(obj runtime.Object) []storage.MatchValue {
return []storage.MatchValue{}
}

// GetSelectableFields returns a field set that represents the object.
func (DefaultStorageStrategy) GetSelectableFields(obj HasObjectMeta) fields.Set {
return generic.ObjectMetaFieldsSet(obj.GetObjectMeta(), true)
Expand Down
2 changes: 2 additions & 0 deletions pkg/builders/resource_interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ type StorageBuilder interface {
Validate(ctx request.Context, obj runtime.Object) field.ErrorList
ValidateUpdate(ctx request.Context, obj, old runtime.Object) field.ErrorList
GetAttrs(obj runtime.Object) (labels.Set, fields.Set, bool, error)
TriggerFunc(obj runtime.Object) []storage.MatchValue
GetSelectableFields(obj HasObjectMeta) fields.Set
BasicMatch(label labels.Selector, field fields.Selector) storage.SelectionPredicate
}
Expand All @@ -74,6 +75,7 @@ type SchemeFns interface {
DefaultingFunction(obj interface{})
GetConversionFunctions() []interface{}
Register(scheme *runtime.Scheme) error
FieldSelectorConversion(label, value string) (string, string, error)
}

type StandardStorageProvider interface {
Expand Down

0 comments on commit 064645b

Please sign in to comment.