From b0e0d3f374fccfd13d891b2425f220dd5f033121 Mon Sep 17 00:00:00 2001 From: Michal Fojtik Date: Mon, 28 Aug 2017 20:02:34 +0200 Subject: [PATCH 1/3] UPSTREAM: 51638: allow to generate extended methods in client-go --- .../src/k8s.io/client-go/testing/actions.go | 39 +++ .../fake/generator_fake_for_type.go | 177 +++++++++-- .../generators/generator_for_type.go | 286 +++++++++++++++--- .../cmd/client-gen/generators/util/tags.go | 192 +++++++++++- .../client-gen/generators/util/tags_test.go | 64 ++++ 5 files changed, 693 insertions(+), 65 deletions(-) diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/testing/actions.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/testing/actions.go index 12a2ecf95b0e..f29ec9e8afe9 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/testing/actions.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/testing/actions.go @@ -47,6 +47,17 @@ func NewGetAction(resource schema.GroupVersionResource, namespace, name string) return action } +func NewGetSubresourceAction(resource schema.GroupVersionResource, namespace, subresource, name string) GetActionImpl { + action := GetActionImpl{} + action.Verb = "get" + action.Resource = resource + action.Subresource = subresource + action.Namespace = namespace + action.Name = name + + return action +} + func NewRootListAction(resource schema.GroupVersionResource, kind schema.GroupVersionKind, opts interface{}) ListActionImpl { action := ListActionImpl{} action.Verb = "list" @@ -70,6 +81,20 @@ func NewListAction(resource schema.GroupVersionResource, kind schema.GroupVersio return action } +func NewListSubresourceAction(resource schema.GroupVersionResource, name, subresource string, kind schema.GroupVersionKind, namespace string, opts interface{}) ListActionImpl { + action := ListActionImpl{} + action.Verb = "list" + action.Resource = resource + action.Subresource = subresource + action.Kind = kind + action.Namespace = namespace + action.Name = name + labelSelector, fieldSelector, _ := ExtractFromListOptions(opts) + action.ListRestrictions = ListRestrictions{labelSelector, fieldSelector} + + return action +} + func NewRootCreateAction(resource schema.GroupVersionResource, object runtime.Object) CreateActionImpl { action := CreateActionImpl{} action.Verb = "create" @@ -172,6 +197,18 @@ func NewUpdateSubresourceAction(resource schema.GroupVersionResource, subresourc return action } +func NewCreateSubresourceAction(resource schema.GroupVersionResource, name, subresource string, namespace string, object runtime.Object) CreateActionImpl { + action := CreateActionImpl{} + action.Verb = "create" + action.Resource = resource + action.Subresource = subresource + action.Namespace = namespace + action.Name = name + action.Object = object + + return action +} + func NewRootDeleteAction(resource schema.GroupVersionResource, name string) DeleteActionImpl { action := DeleteActionImpl{} action.Verb = "delete" @@ -378,6 +415,7 @@ func (a GetActionImpl) GetName() string { type ListActionImpl struct { ActionImpl Kind schema.GroupVersionKind + Name string ListRestrictions ListRestrictions } @@ -391,6 +429,7 @@ func (a ListActionImpl) GetListRestrictions() ListRestrictions { type CreateActionImpl struct { ActionImpl + Name string Object runtime.Object } diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/fake/generator_fake_for_type.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/fake/generator_fake_for_type.go index a66604405492..653136980aa5 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/fake/generator_fake_for_type.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/fake/generator_fake_for_type.go @@ -19,6 +19,7 @@ package fake import ( "io" "path/filepath" + "strings" "k8s.io/gengo/generator" "k8s.io/gengo/namer" @@ -108,6 +109,9 @@ func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io. const pkgClientGoTesting = "k8s.io/client-go/testing" m := map[string]interface{}{ "type": t, + "inputType": t, + "resultType": t, + "subresourcePath": "", "package": pkg, "Package": namer.IC(pkg), "namespaced": !tags.NonNamespaced, @@ -139,7 +143,10 @@ func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io. "NewCreateAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewCreateAction"}), "NewRootWatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootWatchAction"}), "NewWatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewWatchAction"}), + "NewCreateSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewCreateSubresourceAction"}), "NewUpdateSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewUpdateSubresourceAction"}), + "NewGetSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewGetSubresourceAction"}), + "NewListSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewListSubresourceAction"}), "NewRootUpdateSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootUpdateSubresourceAction"}), "NewRootPatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootPatchAction"}), "NewPatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewPatchAction"}), @@ -193,9 +200,88 @@ func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io. sw.Do(patchTemplate, m) } + // generate expansion methods + for _, e := range tags.Extensions { + inputType := *t + resultType := *t + if len(e.InputTypeOverride) > 0 { + if name, pkg := e.Input(); len(pkg) > 0 { + newType := c.Universe.Type(types.Name{Package: pkg, Name: name}) + inputType = *newType + } else { + inputType.Name.Name = e.InputTypeOverride + } + } + if len(e.ResultTypeOverride) > 0 { + if name, pkg := e.Result(); len(pkg) > 0 { + newType := c.Universe.Type(types.Name{Package: pkg, Name: name}) + resultType = *newType + } else { + resultType.Name.Name = e.ResultTypeOverride + } + } + m["inputType"] = &inputType + m["resultType"] = &resultType + m["subresourcePath"] = e.SubResourcePath + + if e.HasVerb("get") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, getSubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, getTemplate), m) + } + } + + if e.HasVerb("list") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, listSubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, listTemplate), m) + } + } + + // TODO: Figure out schemantic for watching a sub-resource. + if e.HasVerb("watch") { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, watchTemplate), m) + } + + if e.HasVerb("create") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, createSubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, createTemplate), m) + } + } + + if e.HasVerb("update") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, updateSubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, updateTemplate), m) + } + } + + // TODO: Figure out schemantic for deleting a sub-resource (what arguments + // are passed, does it need two names? etc. + if e.HasVerb("delete") { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, deleteTemplate), m) + } + + if e.HasVerb("patch") { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, patchTemplate), m) + } + } + return sw.Error() } +// adjustTemplate adjust the origin verb template using the expansion name. +// TODO: Make the verbs in templates parametrized so the strings.Replace() is +// not needed. +func adjustTemplate(name, verbType, template string) string { + return strings.Replace(template, " "+strings.Title(verbType), " "+name, -1) +} + // template for the struct that implements the type's interface var structNamespaced = ` // Fake$.type|publicPlural$ implements $.type|public$Interface @@ -234,6 +320,19 @@ func (c *Fake$.type|publicPlural$) List(opts $.ListOptions|raw$) (result *$.type } ` +var listSubresourceTemplate = ` +// List takes label and field selectors, and returns the list of $.resultType|publicPlural$ that match those selectors. +func (c *Fake$.type|publicPlural$) List($.type|private$Name string, opts $.ListOptions|raw$) (result *$.resultType|raw$List, err error) { + obj, err := c.Fake. + $if .namespaced$Invokes($.NewListSubresourceAction|raw$($.type|allLowercasePlural$Resource, $.type|private$Name, "$.subresourcePath$", $.type|allLowercasePlural$Kind, c.ns, opts), &$.resultType|raw$List{}) + $else$Invokes($.NewRootListAction|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, opts), &$.resultType|raw$List{})$end$ + if obj == nil { + return nil, err + } + return obj.(*$.resultType|raw$List), err +} +` + var listUsingOptionsTemplate = ` // List takes label and field selectors, and returns the list of $.type|publicPlural$ that match those selectors. func (c *Fake$.type|publicPlural$) List(opts $.ListOptions|raw$) (result *$.type|raw$List, err error) { @@ -259,15 +358,28 @@ func (c *Fake$.type|publicPlural$) List(opts $.ListOptions|raw$) (result *$.type ` var getTemplate = ` -// Get takes name of the $.type|private$, and returns the corresponding $.type|private$ object, and an error if there is any. -func (c *Fake$.type|publicPlural$) Get(name string, options $.GetOptions|raw$) (result *$.type|raw$, err error) { +// Get takes name of the $.inputType|private$, and returns the corresponding $.type|private$ object, and an error if there is any. +func (c *Fake$.type|publicPlural$) Get(name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) { obj, err := c.Fake. - $if .namespaced$Invokes($.NewGetAction|raw$($.type|allLowercasePlural$Resource, c.ns, name), &$.type|raw${}) - $else$Invokes($.NewRootGetAction|raw$($.type|allLowercasePlural$Resource, name), &$.type|raw${})$end$ + $if .namespaced$Invokes($.NewGetAction|raw$($.type|allLowercasePlural$Resource, c.ns, name), &$.resultType|raw${}) + $else$Invokes($.NewRootGetAction|raw$($.type|allLowercasePlural$Resource, name), &$.resultType|raw${})$end$ if obj == nil { return nil, err } - return obj.(*$.type|raw$), err + return obj.(*$.resultType|raw$), err +} +` + +var getSubresourceTemplate = ` +// Get takes name of the $.inputType|private$, and returns the corresponding $.type|private$ object, and an error if there is any. +func (c *Fake$.type|publicPlural$) Get($.type|private$Name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) { + obj, err := c.Fake. + $if .namespaced$Invokes($.NewGetSubresourceAction|raw$($.type|allLowercasePlural$Resource, c.ns, "$.subresourcePath$", $.type|private$Name), &$.resultType|raw${}) + $else$Invokes($.NewRootGetAction|raw$($.type|allLowercasePlural$Resource, $.type|private$Name), &$.resultType|raw${})$end$ + if obj == nil { + return nil, err + } + return obj.(*$.resultType|raw$), err } ` @@ -291,30 +403,55 @@ func (c *Fake$.type|publicPlural$) DeleteCollection(options *$.DeleteOptions|raw return err } ` - var createTemplate = ` -// Create takes the representation of a $.type|private$ and creates it. Returns the server's representation of the $.type|private$, and an error, if there is any. -func (c *Fake$.type|publicPlural$) Create($.type|private$ *$.type|raw$) (result *$.type|raw$, err error) { +// Create takes the representation of a $.inputType|private$ and creates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *Fake$.type|publicPlural$) Create($.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) { obj, err := c.Fake. - $if .namespaced$Invokes($.NewCreateAction|raw$($.type|allLowercasePlural$Resource, c.ns, $.type|private$), &$.type|raw${}) - $else$Invokes($.NewRootCreateAction|raw$($.type|allLowercasePlural$Resource, $.type|private$), &$.type|raw${})$end$ + $if .namespaced$Invokes($.NewCreateAction|raw$($.inputType|allLowercasePlural$Resource, c.ns, $.inputType|private$), &$.resultType|raw${}) + $else$Invokes($.NewRootCreateAction|raw$($.inputType|allLowercasePlural$Resource, $.inputType|private$), &$.resultType|raw${})$end$ if obj == nil { return nil, err } - return obj.(*$.type|raw$), err + return obj.(*$.resultType|raw$), err +} +` + +var createSubresourceTemplate = ` +// Create takes the representation of a $.inputType|private$ and creates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *Fake$.type|publicPlural$) Create($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) { + obj, err := c.Fake. + $if .namespaced$Invokes($.NewCreateSubresourceAction|raw$($.type|allLowercasePlural$Resource, $.type|private$Name, "$.subresourcePath$", c.ns, $.inputType|private$), &$.inputType|raw${}) + $else$Invokes($.NewRootCreateAction|raw$($.inputType|allLowercasePlural$Resource, $.inputType|private$), &$.inputType|raw${})$end$ + if obj == nil { + return nil, err + } + return obj.(*$.resultType|raw$), err } ` var updateTemplate = ` -// Update takes the representation of a $.type|private$ and updates it. Returns the server's representation of the $.type|private$, and an error, if there is any. -func (c *Fake$.type|publicPlural$) Update($.type|private$ *$.type|raw$) (result *$.type|raw$, err error) { +// Update takes the representation of a $.inputType|private$ and updates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *Fake$.type|publicPlural$) Update($.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) { obj, err := c.Fake. - $if .namespaced$Invokes($.NewUpdateAction|raw$($.type|allLowercasePlural$Resource, c.ns, $.type|private$), &$.type|raw${}) + $if .namespaced$Invokes($.NewUpdateAction|raw$($.inputType|allLowercasePlural$Resource, c.ns, $.inputType|private$), &$.resultType|raw${}) + $else$Invokes($.NewRootUpdateAction|raw$($.inputType|allLowercasePlural$Resource, $.inputType|private$), &$.resultType|raw${})$end$ + if obj == nil { + return nil, err + } + return obj.(*$.resultType|raw$), err +} +` + +var updateSubresourceTemplate = ` +// Update takes the representation of a $.inputType|private$ and updates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *Fake$.type|publicPlural$) Update($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) { + obj, err := c.Fake. + $if .namespaced$Invokes($.NewUpdateSubresourceAction|raw$($.type|allLowercasePlural$Resource, "$.subresourcePath$", c.ns, $.inputType|private$), &$.inputType|raw${}) $else$Invokes($.NewRootUpdateAction|raw$($.type|allLowercasePlural$Resource, $.type|private$), &$.type|raw${})$end$ if obj == nil { return nil, err } - return obj.(*$.type|raw$), err + return obj.(*$.resultType|raw$), err } ` @@ -342,14 +479,14 @@ func (c *Fake$.type|publicPlural$) Watch(opts $.ListOptions|raw$) ($.watchInterf ` var patchTemplate = ` -// Patch applies the patch and returns the patched $.type|private$. -func (c *Fake$.type|publicPlural$) Patch(name string, pt $.PatchType|raw$, data []byte, subresources ...string) (result *$.type|raw$, err error) { +// Patch applies the patch and returns the patched $.resultType|private$. +func (c *Fake$.type|publicPlural$) Patch(name string, pt $.PatchType|raw$, data []byte, subresources ...string) (result *$.resultType|raw$, err error) { obj, err := c.Fake. - $if .namespaced$Invokes($.NewPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, c.ns, name, data, subresources... ), &$.type|raw${}) - $else$Invokes($.NewRootPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, name, data, subresources...), &$.type|raw${})$end$ + $if .namespaced$Invokes($.NewPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, c.ns, name, data, subresources... ), &$.resultType|raw${}) + $else$Invokes($.NewRootPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, name, data, subresources...), &$.resultType|raw${})$end$ if obj == nil { return nil, err } - return obj.(*$.type|raw$), err + return obj.(*$.resultType|raw$), err } ` diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/generator_for_type.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/generator_for_type.go index 8467a0ba4c15..197c84f740b6 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/generator_for_type.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/generator_for_type.go @@ -77,20 +77,71 @@ func (g *genClientForType) GenerateType(c *generator.Context, t *types.Type, w i if err != nil { return err } + type extendedInterfaceMethod struct { + template string + args map[string]interface{} + } + extendedMethods := []extendedInterfaceMethod{} + for _, e := range tags.Extensions { + inputType := *t + resultType := *t + // TODO: Extract this to some helper method as this code is copied into + // 2 other places. + if len(e.InputTypeOverride) > 0 { + if name, pkg := e.Input(); len(pkg) > 0 { + newType := c.Universe.Type(types.Name{Package: pkg, Name: name}) + inputType = *newType + } else { + inputType.Name.Name = e.InputTypeOverride + } + } + if len(e.ResultTypeOverride) > 0 { + if name, pkg := e.Result(); len(pkg) > 0 { + newType := c.Universe.Type(types.Name{Package: pkg, Name: name}) + resultType = *newType + } else { + resultType.Name.Name = e.ResultTypeOverride + } + } + var updatedVerbtemplate string + if _, exists := subresourceDefaultVerbTemplates[e.VerbType]; e.IsSubresource() && exists { + updatedVerbtemplate = e.VerbName + "(" + strings.TrimPrefix(subresourceDefaultVerbTemplates[e.VerbType], strings.Title(e.VerbType)+"(") + } else { + updatedVerbtemplate = e.VerbName + "(" + strings.TrimPrefix(defaultVerbTemplates[e.VerbType], strings.Title(e.VerbType)+"(") + } + extendedMethods = append(extendedMethods, extendedInterfaceMethod{ + template: updatedVerbtemplate, + args: map[string]interface{}{ + "type": t, + "inputType": &inputType, + "resultType": &resultType, + "DeleteOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "DeleteOptions"}), + "ListOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ListOptions"}), + "GetOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "GetOptions"}), + "PatchType": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/types", Name: "PatchType"}), + }, + }) + } m := map[string]interface{}{ - "type": t, - "package": pkg, - "Package": namer.IC(pkg), - "namespaced": !tags.NonNamespaced, - "Group": namer.IC(g.group), - "GroupVersion": namer.IC(g.group) + namer.IC(g.version), - "DeleteOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "DeleteOptions"}), - "ListOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ListOptions"}), - "GetOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "GetOptions"}), - "PatchType": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/types", Name: "PatchType"}), - "watchInterface": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/watch", Name: "Interface"}), - "RESTClientInterface": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Interface"}), - "schemeParameterCodec": c.Universe.Variable(types.Name{Package: filepath.Join(g.clientsetPackage, "scheme"), Name: "ParameterCodec"}), + "type": t, + "inputType": t, + "resultType": t, + "package": pkg, + "Package": namer.IC(pkg), + "namespaced": !tags.NonNamespaced, + "Group": namer.IC(g.group), + "subresource": false, + "subresourcePath": "", + "GroupVersion": namer.IC(g.group) + namer.IC(g.version), + "DeleteOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "DeleteOptions"}), + "ListOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ListOptions"}), + "GetOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "GetOptions"}), + "PatchType": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/types", Name: "PatchType"}), + "watchInterface": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/watch", Name: "Interface"}), + "RESTClientInterface": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Interface"}), + "schemeParameterCodec": c.Universe.Variable(types.Name{Package: filepath.Join(g.clientsetPackage, "scheme"), Name: "ParameterCodec"}), + "GroupVersionKind": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersionKind"}), + "UnsafeGuessKindToResource": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/api/meta", Name: "UnsafeGuessKindToResource"}), } sw.Do(getterComment, m) @@ -105,7 +156,16 @@ func (g *genClientForType) GenerateType(c *generator.Context, t *types.Type, w i if !genStatus(t) { tags.SkipVerbs = append(tags.SkipVerbs, "updateStatus") } - sw.Do(generateInterface(tags), m) + interfaceSuffix := "" + if len(extendedMethods) > 0 { + interfaceSuffix = "\n" + } + sw.Do("\n"+generateInterface(tags)+interfaceSuffix, m) + // add extended verbs into interface + for _, v := range extendedMethods { + sw.Do(v.template+interfaceSuffix, v.args) + } + } sw.Do(interfaceTemplate4, m) @@ -150,9 +210,88 @@ func (g *genClientForType) GenerateType(c *generator.Context, t *types.Type, w i sw.Do(patchTemplate, m) } + // generate expansion methods + for _, e := range tags.Extensions { + inputType := *t + resultType := *t + if len(e.InputTypeOverride) > 0 { + if name, pkg := e.Input(); len(pkg) > 0 { + newType := c.Universe.Type(types.Name{Package: pkg, Name: name}) + inputType = *newType + } else { + inputType.Name.Name = e.InputTypeOverride + } + } + if len(e.ResultTypeOverride) > 0 { + if name, pkg := e.Result(); len(pkg) > 0 { + newType := c.Universe.Type(types.Name{Package: pkg, Name: name}) + resultType = *newType + } else { + resultType.Name.Name = e.ResultTypeOverride + } + } + m["inputType"] = &inputType + m["resultType"] = &resultType + m["subresourcePath"] = e.SubResourcePath + + if e.HasVerb("get") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, getSubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, getTemplate), m) + } + } + + if e.HasVerb("list") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, listSubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, listTemplate), m) + } + } + + // TODO: Figure out schemantic for watching a sub-resource. + if e.HasVerb("watch") { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, watchTemplate), m) + } + + if e.HasVerb("create") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, createSubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, createTemplate), m) + } + } + + if e.HasVerb("update") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, updateSubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, updateTemplate), m) + } + } + + // TODO: Figure out schemantic for deleting a sub-resource (what arguments + // are passed, does it need two names? etc. + if e.HasVerb("delete") { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, deleteTemplate), m) + } + + if e.HasVerb("patch") { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, patchTemplate), m) + } + } + return sw.Error() } +// adjustTemplate adjust the origin verb template using the expansion name. +// TODO: Make the verbs in templates parametrized so the strings.Replace() is +// not needed. +func adjustTemplate(name, verbType, template string) string { + return strings.Replace(template, " "+strings.Title(verbType), " "+name, -1) +} + func generateInterface(tags util.Tags) string { // need an ordered list here to guarantee order of generated methods. out := []string{} @@ -164,16 +303,23 @@ func generateInterface(tags util.Tags) string { return strings.Join(out, "\n") } +var subresourceDefaultVerbTemplates = map[string]string{ + "create": `Create($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (*$.resultType|raw$, error)`, + "list": `List($.type|private$Name string, opts $.ListOptions|raw$) (*$.resultType|raw$List, error)`, + "update": `Update($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (*$.resultType|raw$, error)`, + "get": `Get($.type|private$Name string, options $.GetOptions|raw$) (*$.resultType|raw$, error)`, +} + var defaultVerbTemplates = map[string]string{ - "create": `Create(*$.type|raw$) (*$.type|raw$, error)`, - "update": `Update(*$.type|raw$) (*$.type|raw$, error)`, + "create": `Create(*$.inputType|raw$) (*$.resultType|raw$, error)`, + "update": `Update(*$.inputType|raw$) (*$.resultType|raw$, error)`, "updateStatus": `UpdateStatus(*$.type|raw$) (*$.type|raw$, error)`, "delete": `Delete(name string, options *$.DeleteOptions|raw$) error`, "deleteCollection": `DeleteCollection(options *$.DeleteOptions|raw$, listOptions $.ListOptions|raw$) error`, - "get": `Get(name string, options $.GetOptions|raw$) (*$.type|raw$, error)`, - "list": `List(opts $.ListOptions|raw$) (*$.type|raw$List, error)`, + "get": `Get(name string, options $.GetOptions|raw$) (*$.resultType|raw$, error)`, + "list": `List(opts $.ListOptions|raw$) (*$.resultType|raw$List, error)`, "watch": `Watch(opts $.ListOptions|raw$) ($.watchInterface|raw$, error)`, - "patch": `Patch(name string, pt $.PatchType|raw$, data []byte, subresources ...string) (result *$.type|raw$, err error)`, + "patch": `Patch(name string, pt $.PatchType|raw$, data []byte, subresources ...string) (result *$.resultType|raw$, err error)`, } // group client will implement this interface. @@ -238,24 +384,40 @@ func new$.type|publicPlural$(c *$.GroupVersion$Client) *$.type|privatePlural$ { } } ` - var listTemplate = ` -// List takes label and field selectors, and returns the list of $.type|publicPlural$ that match those selectors. -func (c *$.type|privatePlural$) List(opts $.ListOptions|raw$) (result *$.type|raw$List, err error) { - result = &$.type|raw$List{} +// List takes label and field selectors, and returns the list of $.resultType|publicPlural$ that match those selectors. +func (c *$.type|privatePlural$) List(opts $.ListOptions|raw$) (result *$.resultType|raw$List, err error) { + result = &$.resultType|raw$List{} + err = c.client.Get(). + $if .namespaced$Namespace(c.ns).$end$ + Resource("$.type|resource$"). + VersionedParams(&opts, $.schemeParameterCodec|raw$). + Do(). + Into(result) + return +} +` + +var listSubresourceTemplate = ` +// List takes $.type|raw$ name, label and field selectors, and returns the list of $.resultType|publicPlural$ that match those selectors. +func (c *$.type|privatePlural$) List($.type|private$Name string, opts $.ListOptions|raw$) (result *$.resultType|raw$List, err error) { + result = &$.resultType|raw$List{} err = c.client.Get(). $if .namespaced$Namespace(c.ns).$end$ Resource("$.type|resource$"). + Name($.type|private$Name). + SubResource("$.subresourcePath$"). VersionedParams(&opts, $.schemeParameterCodec|raw$). Do(). Into(result) return } ` + var getTemplate = ` -// Get takes name of the $.type|private$, and returns the corresponding $.type|private$ object, and an error if there is any. -func (c *$.type|privatePlural$) Get(name string, options $.GetOptions|raw$) (result *$.type|raw$, err error) { - result = &$.type|raw${} +// Get takes name of the $.type|private$, and returns the corresponding $.resultType|private$ object, and an error if there is any. +func (c *$.type|privatePlural$) Get(name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) { + result = &$.resultType|raw${} err = c.client.Get(). $if .namespaced$Namespace(c.ns).$end$ Resource("$.type|resource$"). @@ -267,6 +429,22 @@ func (c *$.type|privatePlural$) Get(name string, options $.GetOptions|raw$) (res } ` +var getSubresourceTemplate = ` +// Get takes name of the $.type|private$, and returns the corresponding $.resultType|raw$ object, and an error if there is any. +func (c *$.type|privatePlural$) Get($.type|private$Name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) { + result = &$.resultType|raw${} + err = c.client.Get(). + $if .namespaced$Namespace(c.ns).$end$ + Resource("$.type|resource$"). + Name($.type|private$Name). + SubResource("$.subresourcePath$"). + VersionedParams(&options, $.schemeParameterCodec|raw$). + Do(). + Into(result) + return +} +` + var deleteTemplate = ` // Delete takes name of the $.type|private$ and deletes it. Returns an error if one occurs. func (c *$.type|privatePlural$) Delete(name string, options *$.DeleteOptions|raw$) error { @@ -293,14 +471,46 @@ func (c *$.type|privatePlural$) DeleteCollection(options *$.DeleteOptions|raw$, } ` +var createSubresourceTemplate = ` +// Create takes the representation of a $.inputType|private$ and creates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *$.type|privatePlural$) Create($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) { + result = &$.resultType|raw${} + err = c.client.Post(). + $if .namespaced$Namespace(c.ns).$end$ + Resource("$.type|resource$"). + Name($.type|private$Name). + SubResource("$.subresourcePath$"). + Body($.inputType|private$). + Do(). + Into(result) + return +} +` + var createTemplate = ` -// Create takes the representation of a $.type|private$ and creates it. Returns the server's representation of the $.type|private$, and an error, if there is any. -func (c *$.type|privatePlural$) Create($.type|private$ *$.type|raw$) (result *$.type|raw$, err error) { - result = &$.type|raw${} +// Create takes the representation of a $.inputType|private$ and creates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *$.type|privatePlural$) Create($.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) { + result = &$.resultType|raw${} err = c.client.Post(). $if .namespaced$Namespace(c.ns).$end$ Resource("$.type|resource$"). - Body($.type|private$). + Body($.inputType|private$). + Do(). + Into(result) + return +} +` + +var updateSubresourceTemplate = ` +// Update takes the top resource name and the representation of a $.inputType|private$ and updates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *$.type|privatePlural$) Update($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) { + result = &$.resultType|raw${} + err = c.client.Put(). + $if .namespaced$Namespace(c.ns).$end$ + Resource("$.type|resource$"). + Name($.type|private$Name). + SubResource("$.subresourcePath$"). + Body($.inputType|private$). Do(). Into(result) return @@ -308,14 +518,14 @@ func (c *$.type|privatePlural$) Create($.type|private$ *$.type|raw$) (result *$. ` var updateTemplate = ` -// Update takes the representation of a $.type|private$ and updates it. Returns the server's representation of the $.type|private$, and an error, if there is any. -func (c *$.type|privatePlural$) Update($.type|private$ *$.type|raw$) (result *$.type|raw$, err error) { - result = &$.type|raw${} +// Update takes the representation of a $.inputType|private$ and updates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *$.type|privatePlural$) Update($.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) { + result = &$.resultType|raw${} err = c.client.Put(). $if .namespaced$Namespace(c.ns).$end$ Resource("$.type|resource$"). - Name($.type|private$.Name). - Body($.type|private$). + Name($.inputType|private$.Name). + Body($.inputType|private$). Do(). Into(result) return @@ -353,9 +563,9 @@ func (c *$.type|privatePlural$) Watch(opts $.ListOptions|raw$) ($.watchInterface ` var patchTemplate = ` -// Patch applies the patch and returns the patched $.type|private$. -func (c *$.type|privatePlural$) Patch(name string, pt $.PatchType|raw$, data []byte, subresources ...string) (result *$.type|raw$, err error) { - result = &$.type|raw${} +// Patch applies the patch and returns the patched $.resultType|private$. +func (c *$.type|privatePlural$) Patch(name string, pt $.PatchType|raw$, data []byte, subresources ...string) (result *$.resultType|raw$, err error) { + result = &$.resultType|raw${} err = c.client.Patch(pt). $if .namespaced$Namespace(c.ns).$end$ Resource("$.type|resource$"). diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/util/tags.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/util/tags.go index 38747ec24c63..0b7d68ca880f 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/util/tags.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/util/tags.go @@ -32,6 +32,7 @@ var supportedTags = []string{ "genclient:skipVerbs", "genclient:noStatus", "genclient:readonly", + "genclient:method", } // SupportedVerbs is a list of supported verbs for +onlyVerbs and +skipVerbs. @@ -54,6 +55,96 @@ var ReadonlyVerbs = []string{ "watch", } +// genClientPrefix is the default prefix for all genclient tags. +const genClientPrefix = "genclient:" + +// unsupportedExtensionVerbs is a list of verbs we don't support generating +// extension client functions for. +var unsupportedExtensionVerbs = []string{ + "updateStatus", + "deleteCollection", + "watch", + "delete", +} + +// inputTypeSupportedVerbs is a list of verb types that supports overriding the +// input argument type. +var inputTypeSupportedVerbs = []string{ + "create", + "update", +} + +// resultTypeSupportedVerbs is a list of verb types that supports overriding the +// resulting type. +var resultTypeSupportedVerbs = []string{ + "create", + "update", + "get", + "list", + "patch", +} + +// Extensions allows to extend the default set of client verbs +// (CRUD+watch+patch+list+deleteCollection) for a given type with custom defined +// verbs. Custom verbs can have custom input and result types and also allow to +// use a sub-resource in a request instead of top-level resource type. +// +// Example: +// +// +genclient:method=UpdateScale,verb=update,subresource=scale,input=Scale,result=Scale +// +// type ReplicaSet struct { ... } +// +// The 'method=UpdateScale' is the name of the client function. +// The 'verb=update' here means the client function will use 'PUT' action. +// The 'subresource=scale' means we will use SubResource template to generate this client function. +// The 'input' is the input type used for creation (function argument). +// The 'result' (not needed in this case) is the result type returned from the +// client function. +// +type extension struct { + // VerbName is the name of the custom verb (Scale, Instantiate, etc..) + VerbName string + // VerbType is the type of the verb (only verbs from SupportedVerbs are + // supported) + VerbType string + // SubResourcePath defines a path to a sub-resource to use in the request. + // (optional) + SubResourcePath string + // InputTypeOverride overrides the input parameter type for the verb. By + // default the original type is used. Overriding the input type only works for + // "create" and "update" verb types. The given type must exists in the same + // package as the original type. + // (optional) + InputTypeOverride string + // ResultTypeOverride overrides the resulting object type for the verb. By + // default the original type is used. Overriding the result type works. + // (optional) + ResultTypeOverride string +} + +// IsSubresource indicates if this extension should generate the sub-resource. +func (e *extension) IsSubresource() bool { + return len(e.SubResourcePath) > 0 +} + +// HasVerb checks if the extension matches the given verb. +func (e *extension) HasVerb(verb string) bool { + return e.VerbType == verb +} + +// Input returns the input override package path and the type. +func (e *extension) Input() (string, string) { + parts := strings.Split(e.InputTypeOverride, ".") + return parts[len(parts)-1], strings.Join(parts[0:len(parts)-1], ".") +} + +// Result returns the result override package path and the type. +func (e *extension) Result() (string, string) { + parts := strings.Split(e.ResultTypeOverride, ".") + return parts[len(parts)-1], strings.Join(parts[0:len(parts)-1], ".") +} + // Tags represents a genclient configuration for a single type. type Tags struct { // +genclient @@ -67,6 +158,8 @@ type Tags struct { // +genclient:skipVerbs=get,update // +genclient:onlyVerbs=create,delete SkipVerbs []string + // +genclient:method=UpdateScale,verb=update,subresource=scale,input=Scale,result=Scale + Extensions []extension } // HasVerb returns true if we should include the given verb in final client interface and @@ -103,25 +196,25 @@ func ParseClientGenTags(lines []string) (Tags, error) { if len(value) > 0 && len(value[0]) > 0 { return ret, fmt.Errorf("+genclient=%s is invalid, use //+genclient if you want to generate client or omit it when you want to disable generation", value) } - _, ret.NonNamespaced = values["genclient:nonNamespaced"] + _, ret.NonNamespaced = values[genClientPrefix+"nonNamespaced"] // Check the old format and error when used if value := values["nonNamespaced"]; len(value) > 0 && len(value[0]) > 0 { return ret, fmt.Errorf("+nonNamespaced=%s is invalid, use //+genclient:nonNamespaced instead", value[0]) } - _, ret.NoVerbs = values["genclient:noVerbs"] - _, ret.NoStatus = values["genclient:noStatus"] + _, ret.NoVerbs = values[genClientPrefix+"noVerbs"] + _, ret.NoStatus = values[genClientPrefix+"noStatus"] onlyVerbs := []string{} - if _, isReadonly := values["genclient:readonly"]; isReadonly { + if _, isReadonly := values[genClientPrefix+"readonly"]; isReadonly { onlyVerbs = ReadonlyVerbs } // Check the old format and error when used if value := values["readonly"]; len(value) > 0 && len(value[0]) > 0 { return ret, fmt.Errorf("+readonly=%s is invalid, use //+genclient:readonly instead", value[0]) } - if v, exists := values["genclient:skipVerbs"]; exists { + if v, exists := values[genClientPrefix+"skipVerbs"]; exists { ret.SkipVerbs = strings.Split(v[0], ",") } - if v, exists := values["genclient:onlyVerbs"]; exists || len(onlyVerbs) > 0 { + if v, exists := values[genClientPrefix+"onlyVerbs"]; exists || len(onlyVerbs) > 0 { if len(v) > 0 { onlyVerbs = append(onlyVerbs, strings.Split(v[0], ",")...) } @@ -146,16 +239,101 @@ func ParseClientGenTags(lines []string) (Tags, error) { } ret.SkipVerbs = skipVerbs } + var err error + if ret.Extensions, err = parseClientExtensions(values); err != nil { + return ret, err + } return ret, validateClientGenTags(values) } +func parseClientExtensions(tags map[string][]string) ([]extension, error) { + var ret []extension + for name, values := range tags { + if !strings.HasPrefix(name, genClientPrefix+"method") { + continue + } + for _, value := range values { + // the value comes in this form: "Foo,verb=create" + ext := extension{} + parts := strings.Split(value, ",") + if len(parts) == 0 { + return nil, fmt.Errorf("invalid of empty extension verb name: %q", value) + } + // The first part represents the name of the extension + ext.VerbName = parts[0] + if len(ext.VerbName) == 0 { + return nil, fmt.Errorf("must specify a verb name (// +genclient:method=Foo,verb=create)") + } + // Parse rest of the arguments + params := parts[1:] + for _, p := range params { + parts := strings.Split(p, "=") + if len(parts) != 2 { + return nil, fmt.Errorf("invalid extension tag specification %q", p) + } + key, val := strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]) + if len(val) == 0 { + return nil, fmt.Errorf("empty value of %q for %q extension", key, ext.VerbName) + } + switch key { + case "verb": + ext.VerbType = val + case "subresource": + ext.SubResourcePath = val + case "input": + ext.InputTypeOverride = val + case "result": + ext.ResultTypeOverride = val + default: + return nil, fmt.Errorf("unknown extension configuration key %q", key) + } + } + // Validate resulting extension configuration + if len(ext.VerbType) == 0 { + return nil, fmt.Errorf("verb type must be specified (use '// +genclient:method=%s,verb=create')", ext.VerbName) + } + if len(ext.ResultTypeOverride) > 0 { + supported := false + for _, v := range resultTypeSupportedVerbs { + if ext.VerbType == v { + supported = true + break + } + } + if !supported { + return nil, fmt.Errorf("%s: result type is not supported for %q verbs (supported verbs: %#v)", ext.VerbName, ext.VerbType, resultTypeSupportedVerbs) + } + } + if len(ext.InputTypeOverride) > 0 { + supported := false + for _, v := range inputTypeSupportedVerbs { + if ext.VerbType == v { + supported = true + break + } + } + if !supported { + return nil, fmt.Errorf("%s: input type is not supported for %q verbs (supported verbs: %#v)", ext.VerbName, ext.VerbType, inputTypeSupportedVerbs) + } + } + for _, t := range unsupportedExtensionVerbs { + if ext.VerbType == t { + return nil, fmt.Errorf("verb %q is not supported by extension generator", ext.VerbType) + } + } + ret = append(ret, ext) + } + } + return ret, nil +} + // validateTags validates that only supported genclient tags were provided. func validateClientGenTags(values map[string][]string) error { for _, k := range supportedTags { delete(values, k) } for key := range values { - if strings.HasPrefix(key, "genclient") { + if strings.HasPrefix(key, strings.TrimSuffix(genClientPrefix, ":")) { return errors.New("unknown tag detected: " + key) } } diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/util/tags_test.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/util/tags_test.go index 531b584835de..a5c938754834 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/util/tags_test.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/util/tags_test.go @@ -82,3 +82,67 @@ func TestParseTags(t *testing.T) { } } } + +func TestParseTagsExtension(t *testing.T) { + testCases := map[string]struct { + lines []string + expectedExtensions []extension + expectError bool + }{ + "simplest extension": { + lines: []string{`+genclient:method=Foo,verb=create`}, + expectedExtensions: []extension{{VerbName: "Foo", VerbType: "create"}}, + }, + "multiple extensions": { + lines: []string{`+genclient:method=Foo,verb=create`, `+genclient:method=Bar,verb=get`}, + expectedExtensions: []extension{{VerbName: "Foo", VerbType: "create"}, {VerbName: "Bar", VerbType: "get"}}, + }, + "extension without verb": { + lines: []string{`+genclient:method`}, + expectError: true, + }, + "extension without verb type": { + lines: []string{`+genclient:method=Foo`}, + expectError: true, + }, + "sub-resource extension": { + lines: []string{`+genclient:method=Foo,verb=create,subresource=bar`}, + expectedExtensions: []extension{{VerbName: "Foo", VerbType: "create", SubResourcePath: "bar"}}, + }, + "output type extension": { + lines: []string{`+genclient:method=Foos,verb=list,result=Bars`}, + expectedExtensions: []extension{{VerbName: "Foos", VerbType: "list", ResultTypeOverride: "Bars"}}, + }, + "input type extension": { + lines: []string{`+genclient:method=Foo,verb=update,input=Bar`}, + expectedExtensions: []extension{{VerbName: "Foo", VerbType: "update", InputTypeOverride: "Bar"}}, + }, + "unknown verb type extension": { + lines: []string{`+genclient:method=Foo,verb=explode`}, + expectedExtensions: nil, + expectError: true, + }, + "invalid verb extension": { + lines: []string{`+genclient:method=Foo,unknown=bar`}, + expectedExtensions: nil, + expectError: true, + }, + "empty verb extension subresource": { + lines: []string{`+genclient:method=Foo,verb=get,subresource=`}, + expectedExtensions: nil, + expectError: true, + }, + } + for key, c := range testCases { + result, err := ParseClientGenTags(c.lines) + if err != nil && !c.expectError { + t.Fatalf("[%s] unexpected error: %v", key, err) + } + if err != nil && c.expectError { + t.Logf("[%s] got expected error: %+v", key, err) + } + if !c.expectError && !reflect.DeepEqual(result.Extensions, c.expectedExtensions) { + t.Errorf("[%s] expected %#+v to be %#+v", key, result.Extensions, c.expectedExtensions) + } + } +} From d3fb931a1999bf9beb1e37eacce1f35482b2c786 Mon Sep 17 00:00:00 2001 From: Michal Fojtik Date: Tue, 29 Aug 2017 13:15:24 +0200 Subject: [PATCH 2/3] apps: add Instantiate, GetScale and UpdateScale client method for deployment config --- pkg/deploy/apis/apps/types.go | 3 ++ pkg/deploy/apis/apps/v1/types.go | 3 ++ .../typed/apps/v1/deploymentconfig.go | 47 +++++++++++++++++++ .../apps/v1/fake/fake_deploymentconfig.go | 34 ++++++++++++++ .../apps/internalversion/deploymentconfig.go | 47 +++++++++++++++++++ .../fake/fake_deploymentconfig.go | 34 ++++++++++++++ 6 files changed, 168 insertions(+) diff --git a/pkg/deploy/apis/apps/types.go b/pkg/deploy/apis/apps/types.go index 66a168f42679..53fe66a091c5 100644 --- a/pkg/deploy/apis/apps/types.go +++ b/pkg/deploy/apis/apps/types.go @@ -123,6 +123,9 @@ const ( ) // +genclient +// +genclient:method=Instantiate,verb=create,subresource=instantiate,input=DeploymentRequest +// +genclient:method=GetScale,verb=get,subresource=scale,result=k8s.io/kubernetes/pkg/apis/extensions/v1beta1.Scale +// +genclient:method=UpdateScale,verb=update,subresource=scale,input=k8s.io/kubernetes/pkg/apis/extensions/v1beta1.Scale,result=k8s.io/kubernetes/pkg/apis/extensions/v1beta1.Scale // DeploymentConfig represents a configuration for a single deployment (represented as a // ReplicationController). It also contains details about changes which resulted in the current diff --git a/pkg/deploy/apis/apps/v1/types.go b/pkg/deploy/apis/apps/v1/types.go index 104efc808a12..6877d7551657 100644 --- a/pkg/deploy/apis/apps/v1/types.go +++ b/pkg/deploy/apis/apps/v1/types.go @@ -9,6 +9,9 @@ import ( ) // +genclient +// +genclient:method=Instantiate,verb=create,subresource=instantiate,input=DeploymentRequest +// +genclient:method=GetScale,verb=get,subresource=scale,result=k8s.io/kubernetes/pkg/apis/extensions/v1beta1.Scale +// +genclient:method=UpdateScale,verb=update,subresource=scale,input=k8s.io/kubernetes/pkg/apis/extensions/v1beta1.Scale,result=k8s.io/kubernetes/pkg/apis/extensions/v1beta1.Scale // Deployment Configs define the template for a pod and manages deploying new images or configuration changes. // A single deployment configuration is usually analogous to a single micro-service. Can support many different diff --git a/pkg/deploy/generated/clientset/typed/apps/v1/deploymentconfig.go b/pkg/deploy/generated/clientset/typed/apps/v1/deploymentconfig.go index a69b3cf17062..14e4036eed2e 100644 --- a/pkg/deploy/generated/clientset/typed/apps/v1/deploymentconfig.go +++ b/pkg/deploy/generated/clientset/typed/apps/v1/deploymentconfig.go @@ -7,6 +7,7 @@ import ( types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" rest "k8s.io/client-go/rest" + v1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" ) // DeploymentConfigsGetter has a method to return a DeploymentConfigInterface. @@ -26,6 +27,10 @@ type DeploymentConfigInterface interface { List(opts meta_v1.ListOptions) (*v1.DeploymentConfigList, error) Watch(opts meta_v1.ListOptions) (watch.Interface, error) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.DeploymentConfig, err error) + Instantiate(deploymentConfigName string, deploymentRequest *v1.DeploymentRequest) (*v1.DeploymentConfig, error) + GetScale(deploymentConfigName string, options meta_v1.GetOptions) (*v1beta1.Scale, error) + UpdateScale(deploymentConfigName string, scale *v1beta1.Scale) (*v1beta1.Scale, error) + DeploymentConfigExpansion } @@ -154,3 +159,45 @@ func (c *deploymentConfigs) Patch(name string, pt types.PatchType, data []byte, Into(result) return } + +// Instantiate takes the representation of a deploymentRequest and creates it. Returns the server's representation of the deploymentConfig, and an error, if there is any. +func (c *deploymentConfigs) Instantiate(deploymentConfigName string, deploymentRequest *v1.DeploymentRequest) (result *v1.DeploymentConfig, err error) { + result = &v1.DeploymentConfig{} + err = c.client.Post(). + Namespace(c.ns). + Resource("deploymentconfigs"). + Name(deploymentConfigName). + SubResource("instantiate"). + Body(deploymentRequest). + Do(). + Into(result) + return +} + +// GetScale takes name of the deploymentConfig, and returns the corresponding v1beta1.Scale object, and an error if there is any. +func (c *deploymentConfigs) GetScale(deploymentConfigName string, options meta_v1.GetOptions) (result *v1beta1.Scale, err error) { + result = &v1beta1.Scale{} + err = c.client.Get(). + Namespace(c.ns). + Resource("deploymentconfigs"). + Name(deploymentConfigName). + SubResource("scale"). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// UpdateScale takes the top resource name and the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *deploymentConfigs) UpdateScale(deploymentConfigName string, scale *v1beta1.Scale) (result *v1beta1.Scale, err error) { + result = &v1beta1.Scale{} + err = c.client.Put(). + Namespace(c.ns). + Resource("deploymentconfigs"). + Name(deploymentConfigName). + SubResource("scale"). + Body(scale). + Do(). + Into(result) + return +} diff --git a/pkg/deploy/generated/clientset/typed/apps/v1/fake/fake_deploymentconfig.go b/pkg/deploy/generated/clientset/typed/apps/v1/fake/fake_deploymentconfig.go index 17ca65535225..9c5cc7689b85 100644 --- a/pkg/deploy/generated/clientset/typed/apps/v1/fake/fake_deploymentconfig.go +++ b/pkg/deploy/generated/clientset/typed/apps/v1/fake/fake_deploymentconfig.go @@ -8,6 +8,7 @@ import ( types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" testing "k8s.io/client-go/testing" + v1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" ) // FakeDeploymentConfigs implements DeploymentConfigInterface @@ -120,3 +121,36 @@ func (c *FakeDeploymentConfigs) Patch(name string, pt types.PatchType, data []by } return obj.(*apps_v1.DeploymentConfig), err } + +// Instantiate takes the representation of a deploymentRequest and creates it. Returns the server's representation of the deploymentConfig, and an error, if there is any. +func (c *FakeDeploymentConfigs) Instantiate(deploymentConfigName string, deploymentRequest *apps_v1.DeploymentRequest) (result *apps_v1.DeploymentConfig, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateSubresourceAction(deploymentconfigsResource, deploymentConfigName, "instantiate", c.ns, deploymentRequest), &apps_v1.DeploymentRequest{}) + + if obj == nil { + return nil, err + } + return obj.(*apps_v1.DeploymentConfig), err +} + +// GetScale takes name of the deploymentConfig, and returns the corresponding deploymentConfig object, and an error if there is any. +func (c *FakeDeploymentConfigs) GetScale(deploymentConfigName string, options v1.GetOptions) (result *v1beta1.Scale, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetSubresourceAction(deploymentconfigsResource, c.ns, "scale", deploymentConfigName), &v1beta1.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Scale), err +} + +// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *FakeDeploymentConfigs) UpdateScale(deploymentConfigName string, scale *v1beta1.Scale) (result *v1beta1.Scale, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(deploymentconfigsResource, "scale", c.ns, scale), &v1beta1.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Scale), err +} diff --git a/pkg/deploy/generated/internalclientset/typed/apps/internalversion/deploymentconfig.go b/pkg/deploy/generated/internalclientset/typed/apps/internalversion/deploymentconfig.go index 65ee6e37fc06..448d9cfdfa81 100644 --- a/pkg/deploy/generated/internalclientset/typed/apps/internalversion/deploymentconfig.go +++ b/pkg/deploy/generated/internalclientset/typed/apps/internalversion/deploymentconfig.go @@ -7,6 +7,7 @@ import ( types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" rest "k8s.io/client-go/rest" + v1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" ) // DeploymentConfigsGetter has a method to return a DeploymentConfigInterface. @@ -26,6 +27,10 @@ type DeploymentConfigInterface interface { List(opts v1.ListOptions) (*apps.DeploymentConfigList, error) Watch(opts v1.ListOptions) (watch.Interface, error) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *apps.DeploymentConfig, err error) + Instantiate(deploymentConfigName string, deploymentRequest *apps.DeploymentRequest) (*apps.DeploymentConfig, error) + GetScale(deploymentConfigName string, options v1.GetOptions) (*v1beta1.Scale, error) + UpdateScale(deploymentConfigName string, scale *v1beta1.Scale) (*v1beta1.Scale, error) + DeploymentConfigExpansion } @@ -154,3 +159,45 @@ func (c *deploymentConfigs) Patch(name string, pt types.PatchType, data []byte, Into(result) return } + +// Instantiate takes the representation of a deploymentRequest and creates it. Returns the server's representation of the deploymentConfig, and an error, if there is any. +func (c *deploymentConfigs) Instantiate(deploymentConfigName string, deploymentRequest *apps.DeploymentRequest) (result *apps.DeploymentConfig, err error) { + result = &apps.DeploymentConfig{} + err = c.client.Post(). + Namespace(c.ns). + Resource("deploymentconfigs"). + Name(deploymentConfigName). + SubResource("instantiate"). + Body(deploymentRequest). + Do(). + Into(result) + return +} + +// GetScale takes name of the deploymentConfig, and returns the corresponding v1beta1.Scale object, and an error if there is any. +func (c *deploymentConfigs) GetScale(deploymentConfigName string, options v1.GetOptions) (result *v1beta1.Scale, err error) { + result = &v1beta1.Scale{} + err = c.client.Get(). + Namespace(c.ns). + Resource("deploymentconfigs"). + Name(deploymentConfigName). + SubResource("scale"). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// UpdateScale takes the top resource name and the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *deploymentConfigs) UpdateScale(deploymentConfigName string, scale *v1beta1.Scale) (result *v1beta1.Scale, err error) { + result = &v1beta1.Scale{} + err = c.client.Put(). + Namespace(c.ns). + Resource("deploymentconfigs"). + Name(deploymentConfigName). + SubResource("scale"). + Body(scale). + Do(). + Into(result) + return +} diff --git a/pkg/deploy/generated/internalclientset/typed/apps/internalversion/fake/fake_deploymentconfig.go b/pkg/deploy/generated/internalclientset/typed/apps/internalversion/fake/fake_deploymentconfig.go index 021f01f534b1..c821f3f25956 100644 --- a/pkg/deploy/generated/internalclientset/typed/apps/internalversion/fake/fake_deploymentconfig.go +++ b/pkg/deploy/generated/internalclientset/typed/apps/internalversion/fake/fake_deploymentconfig.go @@ -8,6 +8,7 @@ import ( types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" testing "k8s.io/client-go/testing" + v1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" ) // FakeDeploymentConfigs implements DeploymentConfigInterface @@ -120,3 +121,36 @@ func (c *FakeDeploymentConfigs) Patch(name string, pt types.PatchType, data []by } return obj.(*apps.DeploymentConfig), err } + +// Instantiate takes the representation of a deploymentRequest and creates it. Returns the server's representation of the deploymentConfig, and an error, if there is any. +func (c *FakeDeploymentConfigs) Instantiate(deploymentConfigName string, deploymentRequest *apps.DeploymentRequest) (result *apps.DeploymentConfig, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateSubresourceAction(deploymentconfigsResource, deploymentConfigName, "instantiate", c.ns, deploymentRequest), &apps.DeploymentRequest{}) + + if obj == nil { + return nil, err + } + return obj.(*apps.DeploymentConfig), err +} + +// GetScale takes name of the deploymentConfig, and returns the corresponding deploymentConfig object, and an error if there is any. +func (c *FakeDeploymentConfigs) GetScale(deploymentConfigName string, options v1.GetOptions) (result *v1beta1.Scale, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetSubresourceAction(deploymentconfigsResource, c.ns, "scale", deploymentConfigName), &v1beta1.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Scale), err +} + +// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *FakeDeploymentConfigs) UpdateScale(deploymentConfigName string, scale *v1beta1.Scale) (result *v1beta1.Scale, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(deploymentconfigsResource, "scale", c.ns, scale), &v1beta1.Scale{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Scale), err +} From c087b7d292fe6f50ec8f398db736fba5601a240b Mon Sep 17 00:00:00 2001 From: Michal Fojtik Date: Tue, 29 Aug 2017 16:14:45 +0200 Subject: [PATCH 3/3] image: add image stream secrets client --- pkg/image/apis/image/types.go | 1 + pkg/image/apis/image/v1/types.go | 1 + .../typed/image/v1/fake/fake_imagestream.go | 12 ++++++++++++ .../clientset/typed/image/v1/imagestream.go | 17 +++++++++++++++++ .../internalversion/fake/fake_imagestream.go | 12 ++++++++++++ .../typed/image/internalversion/imagestream.go | 17 +++++++++++++++++ 6 files changed, 60 insertions(+) diff --git a/pkg/image/apis/image/types.go b/pkg/image/apis/image/types.go index 4fdcff5fbf58..2aae668f3ff9 100644 --- a/pkg/image/apis/image/types.go +++ b/pkg/image/apis/image/types.go @@ -197,6 +197,7 @@ type ImageStreamList struct { } // +genclient +// +genclient:method=Secrets,verb=list,subresource=secrets,result=k8s.io/kubernetes/pkg/api.Secret // ImageStream stores a mapping of tags to images, metadata overrides that are applied // when images are tagged in a stream, and an optional reference to a Docker image diff --git a/pkg/image/apis/image/v1/types.go b/pkg/image/apis/image/v1/types.go index d96167b03323..52c337649f37 100644 --- a/pkg/image/apis/image/v1/types.go +++ b/pkg/image/apis/image/v1/types.go @@ -152,6 +152,7 @@ type ImageStreamList struct { } // +genclient +// +genclient:method=Secrets,verb=list,subresource=secrets,result=k8s.io/kubernetes/pkg/api/v1.Secret // ImageStream stores a mapping of tags to images, metadata overrides that are applied // when images are tagged in a stream, and an optional reference to a Docker image diff --git a/pkg/image/generated/clientset/typed/image/v1/fake/fake_imagestream.go b/pkg/image/generated/clientset/typed/image/v1/fake/fake_imagestream.go index de8800665415..9e3630a6ad1f 100644 --- a/pkg/image/generated/clientset/typed/image/v1/fake/fake_imagestream.go +++ b/pkg/image/generated/clientset/typed/image/v1/fake/fake_imagestream.go @@ -8,6 +8,7 @@ import ( types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" testing "k8s.io/client-go/testing" + api_v1 "k8s.io/kubernetes/pkg/api/v1" ) // FakeImageStreams implements ImageStreamInterface @@ -120,3 +121,14 @@ func (c *FakeImageStreams) Patch(name string, pt types.PatchType, data []byte, s } return obj.(*image_v1.ImageStream), err } + +// Secrets takes label and field selectors, and returns the list of Secrets that match those selectors. +func (c *FakeImageStreams) Secrets(imageStreamName string, opts v1.ListOptions) (result *api_v1.SecretList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListSubresourceAction(imagestreamsResource, imageStreamName, "secrets", imagestreamsKind, c.ns, opts), &api_v1.SecretList{}) + + if obj == nil { + return nil, err + } + return obj.(*api_v1.SecretList), err +} diff --git a/pkg/image/generated/clientset/typed/image/v1/imagestream.go b/pkg/image/generated/clientset/typed/image/v1/imagestream.go index 069c3289b97f..badad22873c6 100644 --- a/pkg/image/generated/clientset/typed/image/v1/imagestream.go +++ b/pkg/image/generated/clientset/typed/image/v1/imagestream.go @@ -7,6 +7,7 @@ import ( types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" rest "k8s.io/client-go/rest" + api_v1 "k8s.io/kubernetes/pkg/api/v1" ) // ImageStreamsGetter has a method to return a ImageStreamInterface. @@ -26,6 +27,8 @@ type ImageStreamInterface interface { List(opts meta_v1.ListOptions) (*v1.ImageStreamList, error) Watch(opts meta_v1.ListOptions) (watch.Interface, error) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.ImageStream, err error) + Secrets(imageStreamName string, opts meta_v1.ListOptions) (*api_v1.SecretList, error) + ImageStreamExpansion } @@ -154,3 +157,17 @@ func (c *imageStreams) Patch(name string, pt types.PatchType, data []byte, subre Into(result) return } + +// Secrets takes v1.ImageStream name, label and field selectors, and returns the list of Secrets that match those selectors. +func (c *imageStreams) Secrets(imageStreamName string, opts meta_v1.ListOptions) (result *api_v1.SecretList, err error) { + result = &api_v1.SecretList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("imagestreams"). + Name(imageStreamName). + SubResource("secrets"). + VersionedParams(&opts, scheme.ParameterCodec). + Do(). + Into(result) + return +} diff --git a/pkg/image/generated/internalclientset/typed/image/internalversion/fake/fake_imagestream.go b/pkg/image/generated/internalclientset/typed/image/internalversion/fake/fake_imagestream.go index 19f28073c39f..e8dfb0f1e7ac 100644 --- a/pkg/image/generated/internalclientset/typed/image/internalversion/fake/fake_imagestream.go +++ b/pkg/image/generated/internalclientset/typed/image/internalversion/fake/fake_imagestream.go @@ -8,6 +8,7 @@ import ( types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" testing "k8s.io/client-go/testing" + api "k8s.io/kubernetes/pkg/api" ) // FakeImageStreams implements ImageStreamInterface @@ -120,3 +121,14 @@ func (c *FakeImageStreams) Patch(name string, pt types.PatchType, data []byte, s } return obj.(*image.ImageStream), err } + +// Secrets takes label and field selectors, and returns the list of Secrets that match those selectors. +func (c *FakeImageStreams) Secrets(imageStreamName string, opts v1.ListOptions) (result *api.SecretList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListSubresourceAction(imagestreamsResource, imageStreamName, "secrets", imagestreamsKind, c.ns, opts), &api.SecretList{}) + + if obj == nil { + return nil, err + } + return obj.(*api.SecretList), err +} diff --git a/pkg/image/generated/internalclientset/typed/image/internalversion/imagestream.go b/pkg/image/generated/internalclientset/typed/image/internalversion/imagestream.go index 945dcb6a32bf..165d63471592 100644 --- a/pkg/image/generated/internalclientset/typed/image/internalversion/imagestream.go +++ b/pkg/image/generated/internalclientset/typed/image/internalversion/imagestream.go @@ -7,6 +7,7 @@ import ( types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" rest "k8s.io/client-go/rest" + api "k8s.io/kubernetes/pkg/api" ) // ImageStreamsGetter has a method to return a ImageStreamInterface. @@ -26,6 +27,8 @@ type ImageStreamInterface interface { List(opts v1.ListOptions) (*image.ImageStreamList, error) Watch(opts v1.ListOptions) (watch.Interface, error) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *image.ImageStream, err error) + Secrets(imageStreamName string, opts v1.ListOptions) (*api.SecretList, error) + ImageStreamExpansion } @@ -154,3 +157,17 @@ func (c *imageStreams) Patch(name string, pt types.PatchType, data []byte, subre Into(result) return } + +// Secrets takes image.ImageStream name, label and field selectors, and returns the list of Secrets that match those selectors. +func (c *imageStreams) Secrets(imageStreamName string, opts v1.ListOptions) (result *api.SecretList, err error) { + result = &api.SecretList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("imagestreams"). + Name(imageStreamName). + SubResource("secrets"). + VersionedParams(&opts, scheme.ParameterCodec). + Do(). + Into(result) + return +}