Skip to content

Commit

Permalink
Add Apply functions to client-gen
Browse files Browse the repository at this point in the history
Kubernetes-commit: 293e07a83666dfc50abb6d2ce23e7dea8c4a46cf
  • Loading branch information
jpbetz authored and k8s-publishing-bot committed Nov 6, 2020
1 parent cc2553e commit ea893dc
Show file tree
Hide file tree
Showing 6 changed files with 295 additions and 54 deletions.
17 changes: 12 additions & 5 deletions cmd/client-gen/args/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,22 @@ type CustomArgs struct {
// PluralExceptions specify list of exceptions used when pluralizing certain types.
// For example 'Endpoints:Endpoints', otherwise the pluralizer will generate 'Endpointes'.
PluralExceptions []string

// ApplyConfigurationPackage is the package of apply builders generated by typebuilder-gen.
// If non-empty, Apply functions are generated for each type and reference the apply builders.
// If empty (""), Apply functions are not generated.
ApplyConfigurationPackage string
}

func NewDefaults() (*args.GeneratorArgs, *CustomArgs) {
genericArgs := args.Default().WithoutDefaultFlagParsing()
customArgs := &CustomArgs{
ClientsetName: "internalclientset",
ClientsetAPIPath: "/apis",
ClientsetOnly: false,
FakeClient: true,
PluralExceptions: []string{"Endpoints:Endpoints"},
ClientsetName: "internalclientset",
ClientsetAPIPath: "/apis",
ClientsetOnly: false,
FakeClient: true,
PluralExceptions: []string{"Endpoints:Endpoints"},
ApplyConfigurationPackage: "",
}
genericArgs.CustomArgs = customArgs
genericArgs.InputDirs = DefaultInputDirs
Expand All @@ -84,6 +90,7 @@ func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet, inputBase string) {
pflag.BoolVar(&ca.FakeClient, "fake-clientset", ca.FakeClient, "when set, client-gen will generate the fake clientset that can be used in tests")

fs.StringSliceVar(&ca.PluralExceptions, "plural-exceptions", ca.PluralExceptions, "list of comma separated plural exception definitions in Type:PluralizedType form")
fs.StringVar(&ca.ApplyConfigurationPackage, "apply-configuration-package", ca.ApplyConfigurationPackage, "optional package of apply configurations, generated by applyconfiguration-gen, that are required to generate Apply functions for each type in the clientset. By default Apply functions are not generated.")

// support old flags
fs.SetNormalizeFunc(mapFlagName("clientset-path", "output-package", fs.GetNormalizeFunc()))
Expand Down
22 changes: 12 additions & 10 deletions cmd/client-gen/generators/client_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func DefaultNameSystem() string {
return "public"
}

func packageForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, clientsetPackage string, groupPackageName string, groupGoName string, apiPath string, srcTreePath string, inputPackage string, boilerplate []byte) generator.Package {
func packageForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, clientsetPackage string, groupPackageName string, groupGoName string, apiPath string, srcTreePath string, inputPackage string, applyBuilderPackage string, boilerplate []byte) generator.Package {
groupVersionClientPackage := filepath.Join(clientsetPackage, "typed", strings.ToLower(groupPackageName), strings.ToLower(gv.Version.NonEmpty()))
return &generator.DefaultPackage{
PackageName: strings.ToLower(gv.Version.NonEmpty()),
Expand All @@ -151,13 +151,15 @@ func packageForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, cli
DefaultGen: generator.DefaultGen{
OptionalName: strings.ToLower(c.Namers["private"].Name(t)),
},
outputPackage: groupVersionClientPackage,
clientsetPackage: clientsetPackage,
group: gv.Group.NonEmpty(),
version: gv.Version.String(),
groupGoName: groupGoName,
typeToMatch: t,
imports: generator.NewImportTracker(),
outputPackage: groupVersionClientPackage,
inputPackage: inputPackage,
clientsetPackage: clientsetPackage,
applyConfigurationPackage: applyBuilderPackage,
group: gv.Group.NonEmpty(),
version: gv.Version.String(),
groupGoName: groupGoName,
typeToMatch: t,
imports: generator.NewImportTracker(),
})
}

Expand Down Expand Up @@ -390,9 +392,9 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
gv := clientgentypes.GroupVersion{Group: group.Group, Version: version.Version}
types := gvToTypes[gv]
inputPath := gvPackages[gv]
packageList = append(packageList, packageForGroup(gv, orderer.OrderTypes(types), clientsetPackage, group.PackageName, groupGoNames[gv], customArgs.ClientsetAPIPath, arguments.OutputBase, inputPath, boilerplate))
packageList = append(packageList, packageForGroup(gv, orderer.OrderTypes(types), clientsetPackage, group.PackageName, groupGoNames[gv], customArgs.ClientsetAPIPath, arguments.OutputBase, inputPath, customArgs.ApplyConfigurationPackage, boilerplate))
if customArgs.FakeClient {
packageList = append(packageList, fake.PackageForGroup(gv, orderer.OrderTypes(types), clientsetPackage, group.PackageName, groupGoNames[gv], inputPath, boilerplate))
packageList = append(packageList, fake.PackageForGroup(gv, orderer.OrderTypes(types), clientsetPackage, group.PackageName, groupGoNames[gv], inputPath, customArgs.ApplyConfigurationPackage, boilerplate))
}
}
}
Expand Down
17 changes: 9 additions & 8 deletions cmd/client-gen/generators/fake/fake_client_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
)

func PackageForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, clientsetPackage string, groupPackageName string, groupGoName string, inputPackage string, boilerplate []byte) generator.Package {
func PackageForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, clientsetPackage string, groupPackageName string, groupGoName string, inputPackage string, applyBuilderPackage string, boilerplate []byte) generator.Package {
outputPackage := filepath.Join(clientsetPackage, "typed", strings.ToLower(groupPackageName), strings.ToLower(gv.Version.NonEmpty()), "fake")
// TODO: should make this a function, called by here and in client-generator.go
realClientPackage := filepath.Join(clientsetPackage, "typed", strings.ToLower(groupPackageName), strings.ToLower(gv.Version.NonEmpty()))
Expand All @@ -54,13 +54,14 @@ func PackageForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, cli
DefaultGen: generator.DefaultGen{
OptionalName: "fake_" + strings.ToLower(c.Namers["private"].Name(t)),
},
outputPackage: outputPackage,
inputPackage: inputPackage,
group: gv.Group.NonEmpty(),
version: gv.Version.String(),
groupGoName: groupGoName,
typeToMatch: t,
imports: generator.NewImportTracker(),
outputPackage: outputPackage,
inputPackage: inputPackage,
group: gv.Group.NonEmpty(),
version: gv.Version.String(),
groupGoName: groupGoName,
typeToMatch: t,
imports: generator.NewImportTracker(),
applyBuilderPackage: applyBuilderPackage,
})
}

Expand Down
86 changes: 79 additions & 7 deletions cmd/client-gen/generators/fake/generator_fake_for_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package fake

import (
"io"
gopath "path"
"path/filepath"
"strings"

Expand All @@ -32,13 +33,14 @@ import (
// genFakeForType produces a file for each top-level type.
type genFakeForType struct {
generator.DefaultGen
outputPackage string
group string
version string
groupGoName string
inputPackage string
typeToMatch *types.Type
imports namer.ImportTracker
outputPackage string
group string
version string
groupGoName string
inputPackage string
typeToMatch *types.Type
imports namer.ImportTracker
applyBuilderPackage string
}

var _ generator.Generator = &genFakeForType{}
Expand Down Expand Up @@ -127,12 +129,15 @@ func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io.
"GetOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "GetOptions"}),
"ListOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ListOptions"}),
"PatchOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "PatchOptions"}),
"ApplyOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ApplyOptions"}),
"UpdateOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "UpdateOptions"}),
"Everything": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/labels", Name: "Everything"}),
"GroupVersionResource": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersionResource"}),
"GroupVersionKind": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersionKind"}),
"PatchType": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/types", Name: "PatchType"}),
"ApplyPatchType": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/types", Name: "ApplyPatchType"}),
"watchInterface": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/watch", Name: "Interface"}),
"jsonMarshal": c.Universe.Type(types.Name{Package: "encoding/json", Name: "Marshal"}),

"NewRootListAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootListAction"}),
"NewListAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewListAction"}),
Expand Down Expand Up @@ -161,6 +166,13 @@ func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io.
"ExtractFromListOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "ExtractFromListOptions"}),
}

generateApply := len(g.applyBuilderPackage) > 0
if generateApply {
// Generated apply builder type references required for generated Apply function
_, gvString := util.ParsePathGroupVersion(g.inputPackage)
m["applyConfig"] = types.Ref(gopath.Join(g.applyBuilderPackage, gvString), t.Name.Name+"ApplyConfiguration")
}

if tags.NonNamespaced {
sw.Do(structNonNamespaced, m)
} else {
Expand Down Expand Up @@ -205,6 +217,12 @@ func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io.
if tags.HasVerb("patch") {
sw.Do(patchTemplate, m)
}
if tags.HasVerb("apply") && generateApply {
sw.Do(applyTemplate, m)
}
if tags.HasVerb("applyStatus") && generateApply && genStatus(t) {
sw.Do(applyStatusTemplate, m)
}

// generate extended client methods
for _, e := range tags.Extensions {
Expand Down Expand Up @@ -273,6 +291,11 @@ func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io.
if e.HasVerb("patch") {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, patchTemplate), m)
}

if e.HasVerb("apply") && generateApply {
// TODO: Support apply on arbitrary subresource once it is supported by the api-server.
sw.Do(adjustTemplate(e.VerbName, e.VerbType, applyTemplate), m)
}
}

return sw.Error()
Expand Down Expand Up @@ -480,3 +503,52 @@ func (c *Fake$.type|publicPlural$) Patch(ctx context.Context, name string, pt $.
return obj.(*$.resultType|raw$), err
}
`

var applyTemplate = `
// Apply takes the given apply declarative configuration, applies it and returns the applied $.resultType|private$.
func (c *Fake$.type|publicPlural$) Apply(ctx context.Context, $.inputType|private$ *$.applyConfig|raw$, opts $.ApplyOptions|raw$) (result *$.resultType|raw$, err error) {
if $.inputType|private$ == nil {
return nil, fmt.Errorf("$.inputType|private$ provided to Apply must not be nil")
}
data, err := $.jsonMarshal|raw$($.inputType|private$)
if err != nil {
return nil, err
}
name := $.inputType|private$.Name
if name == nil {
return nil, fmt.Errorf("$.inputType|private$.Name must be provided to Apply")
}
obj, err := c.Fake.
$if .namespaced$Invokes($.NewPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, c.ns, *name, $.ApplyPatchType|raw$, data), &$.resultType|raw${})
$else$Invokes($.NewRootPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, *name, $.ApplyPatchType|raw$, data), &$.resultType|raw${})$end$
if obj == nil {
return nil, err
}
return obj.(*$.resultType|raw$), err
}
`

var applyStatusTemplate = `
// ApplyStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus().
func (c *Fake$.type|publicPlural$) ApplyStatus(ctx context.Context, $.inputType|private$ *$.applyConfig|raw$, opts $.ApplyOptions|raw$) (result *$.resultType|raw$, err error) {
if $.inputType|private$ == nil {
return nil, fmt.Errorf("$.inputType|private$ provided to Apply must not be nil")
}
data, err := $.jsonMarshal|raw$($.inputType|private$)
if err != nil {
return nil, err
}
name := $.inputType|private$.Name
if name == nil {
return nil, fmt.Errorf("$.inputType|private$.Name must be provided to Apply")
}
obj, err := c.Fake.
$if .namespaced$Invokes($.NewPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, c.ns, *name, $.ApplyPatchType|raw$, data, "status"), &$.resultType|raw${})
$else$Invokes($.NewRootPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, *name, $.ApplyPatchType|raw$, data, "status"), &$.resultType|raw${})$end$
if obj == nil {
return nil, err
}
return obj.(*$.resultType|raw$), err
}
`
Loading

0 comments on commit ea893dc

Please sign in to comment.