From 21971e217d674d79251997e4f4e96733f4650bbe Mon Sep 17 00:00:00 2001 From: Tim Hockin Date: Sat, 24 Sep 2016 21:05:52 -0700 Subject: [PATCH 1/7] Log code generators to stderr --- Makefile.generated_files | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile.generated_files b/Makefile.generated_files index 83835b4c2f0..df1c34da372 100644 --- a/Makefile.generated_files +++ b/Makefile.generated_files @@ -216,6 +216,7 @@ gen_deepcopy: $(DEEPCOPY_FILES) if [[ -f $(META_DIR)/$(DEEPCOPY_GEN).todo ]]; then \ ./hack/run-in-gopath.sh $(DEEPCOPY_GEN) \ --v $(KUBE_VERBOSE) \ + --logtostderr \ -i $$(cat $(META_DIR)/$(DEEPCOPY_GEN).todo | paste -sd, -) \ --bounding-dirs $(PRJ_SRC_PATH) \ -O $(DEEPCOPY_BASENAME); \ @@ -318,6 +319,7 @@ gen_openapi: $(OPENAPI_FILES) if [[ -f $(META_DIR)/$(OPENAPI_GEN).todo ]]; then \ ./hack/run-in-gopath.sh $(OPENAPI_GEN) \ --v $(KUBE_VERBOSE) \ + --logtostderr \ -i $$(cat $(META_DIR)/$(OPENAPI_GEN).todo | paste -sd, -) \ -O $(OPENAPI_BASENAME); \ fi @@ -432,6 +434,7 @@ gen_conversion: $(CONVERSION_FILES) if [[ -f $(META_DIR)/$(CONVERSION_GEN).todo ]]; then \ ./hack/run-in-gopath.sh $(CONVERSION_GEN) \ --v $(KUBE_VERBOSE) \ + --logtostderr \ -i $$(cat $(META_DIR)/$(CONVERSION_GEN).todo | paste -sd, -) \ -O $(CONVERSION_BASENAME); \ fi From 17b64fc3d61ff9962e7fcbf0e20c366d1f871ef1 Mon Sep 17 00:00:00 2001 From: Tim Hockin Date: Sat, 24 Sep 2016 21:06:44 -0700 Subject: [PATCH 2/7] Better warning string in failed conversion gen --- cmd/libs/go2idl/conversion-gen/generators/conversion.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/libs/go2idl/conversion-gen/generators/conversion.go b/cmd/libs/go2idl/conversion-gen/generators/conversion.go index 3606d5f8e1c..b04463e75a9 100644 --- a/cmd/libs/go2idl/conversion-gen/generators/conversion.go +++ b/cmd/libs/go2idl/conversion-gen/generators/conversion.go @@ -359,7 +359,7 @@ func isDirectlyConvertible(in, out *types.Type, manualConversions conversionFunc // Check if there is an out member with that name. outMember, found := findMember(out, inMember.Name) if !found { - glog.V(5).Infof("%s.%s is not directly convertible to %s because the destination struct field did not exist", in.Name, inMember.Name, out.Name) + glog.V(5).Infof("%s is not directly convertible to %s because the destination field %q did not exist", in.Name, out.Name, inMember.Name) return false } convertible = convertible && isConvertible(inMember.Type, outMember.Type, manualConversions) From 87abf78bb73251de5d76a61409bc71ecb92350af Mon Sep 17 00:00:00 2001 From: Tim Hockin Date: Sun, 25 Sep 2016 10:17:16 -0700 Subject: [PATCH 3/7] Minor cleanups in conversion gen --- .../go2idl/conversion-gen/generators/conversion.go | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/cmd/libs/go2idl/conversion-gen/generators/conversion.go b/cmd/libs/go2idl/conversion-gen/generators/conversion.go index b04463e75a9..513cd6e2241 100644 --- a/cmd/libs/go2idl/conversion-gen/generators/conversion.go +++ b/cmd/libs/go2idl/conversion-gen/generators/conversion.go @@ -137,6 +137,7 @@ func getManualConversionFunctions(context *generator.Context, pkg *types.Package continue } // Now check if the name satisfies the convention. + // TODO: This should call the Namer directly. args := argsFromType(inType.Elem, outType.Elem) sw.Do("Convert_$.inType|public$_To_$.outType|public$", args) if f.Name.Name == buffer.String() { @@ -210,11 +211,7 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat inputs := sets.NewString(context.Inputs...) packages := generator.Packages{} header := append([]byte(fmt.Sprintf("// +build !%s\n\n", arguments.GeneratedBuildTag)), boilerplate...) - header = append(header, []byte( - ` -// This file was autogenerated by conversion-gen. Do not edit it manually! - -`)...) + header = append(header, []byte("\n// This file was autogenerated by conversion-gen. Do not edit it manually!\n\n")...) // Accumulate pre-existing conversion and default functions. // TODO: This is too ad-hoc. We need a better way. @@ -290,10 +287,9 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat PackagePath: pkg.Path, HeaderText: header, GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { - generators = []generator.Generator{} - generators = append( - generators, NewGenConversion(arguments.OutputFileBaseName, pkg.Path, manualConversions, manualDefaults, peerPkgs)) - return generators + return []generator.Generator{ + NewGenConversion(arguments.OutputFileBaseName, pkg.Path, manualConversions, manualDefaults, peerPkgs), + } }, FilterFunc: func(c *generator.Context, t *types.Type) bool { return t.Name.Package == pkg.Path From 210a634bccc4ac49d9bbe405af0c279d96e723c8 Mon Sep 17 00:00:00 2001 From: Tim Hockin Date: Sun, 25 Sep 2016 10:30:40 -0700 Subject: [PATCH 4/7] Remove useless conversion-gen pre-filter --- .../conversion-gen/generators/conversion.go | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/cmd/libs/go2idl/conversion-gen/generators/conversion.go b/cmd/libs/go2idl/conversion-gen/generators/conversion.go index 513cd6e2241..27c39888aa7 100644 --- a/cmd/libs/go2idl/conversion-gen/generators/conversion.go +++ b/cmd/libs/go2idl/conversion-gen/generators/conversion.go @@ -254,33 +254,6 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat getManualDefaultingFunctions(context, context.Universe[pp], manualDefaults) } - pkgNeedsGeneration := false - for _, t := range pkg.Types { - // Check whether this type can be auto-converted to the peer - // package type. - peerType := getPeerTypeFor(context, t, peerPkgs) - if peerType == nil { - // We did not find a corresponding type. - continue - } - if namer.IsPrivateGoName(peerType.Name.Name) { - // We won't be able to convert to a private type. - glog.V(5).Infof(" found a peer type %v, but it is a private name", t) - continue - } - - // If we can generate conversion in any direction, we should - // generate this package. - if isConvertible(t, peerType, manualConversions) || isConvertible(peerType, t, manualConversions) { - pkgNeedsGeneration = true - break - } - } - if !pkgNeedsGeneration { - glog.V(5).Infof(" no viable conversions, not generating for this package") - continue - } - packages = append(packages, &generator.DefaultPackage{ PackageName: filepath.Base(pkg.Path), From 3023decd000a0cb8cdbe077ef895b9a0739fddfb Mon Sep 17 00:00:00 2001 From: Tim Hockin Date: Mon, 26 Sep 2016 00:34:25 -0700 Subject: [PATCH 5/7] Renames for readability in conversion-gen --- .../conversion-gen/generators/conversion.go | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/cmd/libs/go2idl/conversion-gen/generators/conversion.go b/cmd/libs/go2idl/conversion-gen/generators/conversion.go index 27c39888aa7..e4c0af9d87b 100644 --- a/cmd/libs/go2idl/conversion-gen/generators/conversion.go +++ b/cmd/libs/go2idl/conversion-gen/generators/conversion.go @@ -693,68 +693,68 @@ func (g *genConversion) doSlice(inType, outType *types.Type, sw *generator.Snipp } func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.SnippetWriter) { - for _, m := range inType.Members { + for _, inMember := range inType.Members { // Check if this member is excluded from conversion - if tagvals := extractTag(m.CommentLines); tagvals != nil && tagvals[0] == "false" { + if tagvals := extractTag(inMember.CommentLines); tagvals != nil && tagvals[0] == "false" { continue } - outMember, isOutMember := findMember(outType, m.Name) - if !isOutMember { + outMember, found := findMember(outType, inMember.Name) + if !found { // Since this object wasn't filtered out, this means that // this field has "+k8s:conversion-gen=false" comment to ignore it. continue } - t, outT := m.Type, outMember.Type + inMemberType, outMemberType := inMember.Type, outMember.Type // create a copy of both underlying types but give them the top level alias name (since aliases // are assignable) - if underlying := unwrapAlias(t); underlying != t { + if underlying := unwrapAlias(inMemberType); underlying != inMemberType { copied := *underlying - copied.Name = t.Name - t = &copied + copied.Name = inMemberType.Name + inMemberType = &copied } - if underlying := unwrapAlias(outT); underlying != outT { + if underlying := unwrapAlias(outMemberType); underlying != outMemberType { copied := *underlying - copied.Name = outT.Name - outT = &copied + copied.Name = outMemberType.Name + outMemberType = &copied } args := map[string]interface{}{ - "inType": t, - "outType": outT, - "name": m.Name, + "inType": inMemberType, + "outType": outMemberType, + "name": inMember.Name, } // check based on the top level name, not the underlying names - if function, ok := g.preexists(m.Type, outMember.Type); ok { + if function, ok := g.preexists(inMember.Type, outMember.Type); ok { args["function"] = function sw.Do("if err := $.function|raw$(&in.$.name$, &out.$.name$, s); err != nil {\n", args) sw.Do("return err\n", nil) sw.Do("}\n", nil) continue } - switch t.Kind { + switch inMemberType.Kind { case types.Builtin: - if t == outT { + if inMemberType == outMemberType { sw.Do("out.$.name$ = in.$.name$\n", args) } else { sw.Do("out.$.name$ = $.outType|raw$(in.$.name$)\n", args) } case types.Map, types.Slice, types.Pointer: - if g.isDirectlyAssignable(t, outT) { + if g.isDirectlyAssignable(inMemberType, outMemberType) { sw.Do("out.$.name$ = in.$.name$\n", args) continue } sw.Do("if in.$.name$ != nil {\n", args) sw.Do("in, out := &in.$.name$, &out.$.name$\n", args) - g.generateFor(t, outT, sw) + g.generateFor(inMemberType, outMemberType, sw) sw.Do("} else {\n", nil) sw.Do("out.$.name$ = nil\n", args) sw.Do("}\n", nil) case types.Struct: - if g.isDirectlyAssignable(t, outT) { + if g.isDirectlyAssignable(inMemberType, outMemberType) { sw.Do("out.$.name$ = in.$.name$\n", args) continue } - if g.convertibleOnlyWithinPackage(t, outT) { + if g.convertibleOnlyWithinPackage(inMemberType, outMemberType) { sw.Do("if err := "+nameTmpl+"(&in.$.name$, &out.$.name$, s); err != nil {\n", args) } else { sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil) @@ -763,14 +763,14 @@ func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.Snip sw.Do("return err\n", nil) sw.Do("}\n", nil) case types.Alias: - if isDirectlyAssignable(t, outT) { - if t == outT { + if isDirectlyAssignable(inMemberType, outMemberType) { + if inMemberType == outMemberType { sw.Do("out.$.name$ = in.$.name$\n", args) } else { sw.Do("out.$.name$ = $.outType|raw$(in.$.name$)\n", args) } } else { - if g.convertibleOnlyWithinPackage(t, outT) { + if g.convertibleOnlyWithinPackage(inMemberType, outMemberType) { sw.Do("if err := "+nameTmpl+"(&in.$.name$, &out.$.name$, s); err != nil {\n", args) } else { sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil) @@ -780,7 +780,7 @@ func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.Snip sw.Do("}\n", nil) } default: - if g.convertibleOnlyWithinPackage(t, outT) { + if g.convertibleOnlyWithinPackage(inMemberType, outMemberType) { sw.Do("if err := "+nameTmpl+"(&in.$.name$, &out.$.name$, s); err != nil {\n", args) } else { sw.Do("// TODO: Inefficient conversion - can we improve it?\n", nil) From 7efb2d473868d89f840687f958bf8d7f613446b0 Mon Sep 17 00:00:00 2001 From: Tim Hockin Date: Sun, 25 Sep 2016 22:32:59 -0700 Subject: [PATCH 6/7] Always emit autoConvert funcs, but call for help Previously we refused to emit 'autoConvert_*' functions if any field was not convertible. The way around this was to write manual Conversion functions, but to do so safely you must handle every fields. Huge opportunity for errors. This PR cleans up the filtering such that it only operates on types that should be converted (remove a lot of code) and tracks when fields are skipped. In that case, it emits an 'autoConvert' function but not a public 'Convert' function. If there is no manual function, the compile will fail. This also means that manual conversion functions can call autoConvert functions and then "patch up" what they need. --- .../conversion-gen/generators/conversion.go | 158 +++++------------- .../apis/core/v1/zz_generated.conversion.go | 35 ++++ .../apps/v1alpha1/zz_generated.conversion.go | 45 +++++ .../v1beta1/zz_generated.conversion.go | 74 ++++++++ 4 files changed, 192 insertions(+), 120 deletions(-) create mode 100644 federation/apis/core/v1/zz_generated.conversion.go diff --git a/cmd/libs/go2idl/conversion-gen/generators/conversion.go b/cmd/libs/go2idl/conversion-gen/generators/conversion.go index e4c0af9d87b..210f20725bb 100644 --- a/cmd/libs/go2idl/conversion-gen/generators/conversion.go +++ b/cmd/libs/go2idl/conversion-gen/generators/conversion.go @@ -284,87 +284,14 @@ func findMember(t *types.Type, name string) (types.Member, bool) { return types.Member{}, false } -func isConvertible(in, out *types.Type, manualConversions conversionFuncMap) bool { - // If there is pre-existing conversion function, return true immediately. - if _, ok := manualConversions[conversionPair{in, out}]; ok { - return true - } - return isDirectlyConvertible(in, out, manualConversions) -} - -func isDirectlyConvertible(in, out *types.Type, manualConversions conversionFuncMap) bool { - // If one of the types is Alias, resolve it. - if in.Kind == types.Alias { - return isConvertible(in.Underlying, out, manualConversions) - } - if out.Kind == types.Alias { - return isConvertible(in, out.Underlying, manualConversions) - } - - if in == out { - return true - } - if in.Kind != out.Kind { - return false - } - switch in.Kind { - case types.Builtin, types.Struct, types.Map, types.Slice, types.Pointer: - default: - // We don't support conversion of other types yet. - return false - } - - switch in.Kind { - case types.Builtin: - // TODO: Support more conversion types. - return types.IsInteger(in) && types.IsInteger(out) - case types.Struct: - convertible := true - for _, inMember := range in.Members { - // Check if this member is excluded from conversion - if tagvals := extractTag(inMember.CommentLines); tagvals != nil && tagvals[0] == "false" { - continue - } - // Check if there is an out member with that name. - outMember, found := findMember(out, inMember.Name) - if !found { - glog.V(5).Infof("%s is not directly convertible to %s because the destination field %q did not exist", in.Name, out.Name, inMember.Name) - return false - } - convertible = convertible && isConvertible(inMember.Type, outMember.Type, manualConversions) - } - return convertible - case types.Map: - return isConvertible(in.Key, out.Key, manualConversions) && isConvertible(in.Elem, out.Elem, manualConversions) - case types.Slice: - return isConvertible(in.Elem, out.Elem, manualConversions) - case types.Pointer: - return isConvertible(in.Elem, out.Elem, manualConversions) - } - glog.Fatalf("All other types should be filtered before") - return false -} - // unwrapAlias recurses down aliased types to find the bedrock type. func unwrapAlias(in *types.Type) *types.Type { - if in.Kind == types.Alias { - return unwrapAlias(in.Underlying) + for in.Kind == types.Alias { + in = in.Underlying } return in } -func areTypesAliased(in, out *types.Type) bool { - // If one of the types is Alias, resolve it. - if in.Kind == types.Alias { - return areTypesAliased(in.Underlying, out) - } - if out.Kind == types.Alias { - return areTypesAliased(in, out.Underlying) - } - - return in == out -} - const ( runtimePackagePath = "k8s.io/kubernetes/pkg/runtime" conversionPackagePath = "k8s.io/kubernetes/pkg/conversion" @@ -378,7 +305,8 @@ type genConversion struct { manualConversions conversionFuncMap manualDefaulters defaulterFuncMap imports namer.ImportTracker - typesForInit []conversionPair + types []*types.Type + skippedFields map[*types.Type][]string } func NewGenConversion(sanitizedName, targetPackage string, manualConversions conversionFuncMap, manualDefaulters defaulterFuncMap, peerPkgs []string) generator.Generator { @@ -391,7 +319,8 @@ func NewGenConversion(sanitizedName, targetPackage string, manualConversions con manualConversions: manualConversions, manualDefaulters: manualDefaulters, imports: generator.NewImportTracker(), - typesForInit: make([]conversionPair, 0), + types: []*types.Type{}, + skippedFields: map[*types.Type][]string{}, } } @@ -456,18 +385,9 @@ func (g *genConversion) Filter(c *generator.Context, t *types.Type) bool { if !g.convertibleOnlyWithinPackage(t, peerType) { return false } - // We explicitly return true if any conversion is possible - this needs - // to be checked again while generating code for that type. - convertible := false - if isConvertible(t, peerType, g.manualConversions) { - g.typesForInit = append(g.typesForInit, conversionPair{t, peerType}) - convertible = true - } - if isConvertible(peerType, t, g.manualConversions) { - g.typesForInit = append(g.typesForInit, conversionPair{peerType, t}) - convertible = true - } - return convertible + + g.types = append(g.types, t) + return true } func (g *genConversion) isOtherPackage(pkg string) bool { @@ -525,8 +445,10 @@ func (g *genConversion) Init(c *generator.Context, w io.Writer) error { sw.Do("// Public to allow building arbitrary schemes.\n", nil) sw.Do("func RegisterConversions(scheme $.|raw$) error {\n", schemePtr) sw.Do("return scheme.AddGeneratedConversionFuncs(\n", nil) - for _, conv := range g.typesForInit { - sw.Do(nameTmpl+",\n", argsFromType(conv.inType, conv.outType)) + for _, t := range g.types { + peerType := getPeerTypeFor(c, t, g.peerPackages) + sw.Do(nameTmpl+",\n", argsFromType(t, peerType)) + sw.Do(nameTmpl+",\n", argsFromType(peerType, t)) } sw.Do(")\n", nil) sw.Do("}\n\n", nil) @@ -535,33 +457,10 @@ func (g *genConversion) Init(c *generator.Context, w io.Writer) error { func (g *genConversion) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { glog.V(5).Infof("generating for type %v", t) - sw := generator.NewSnippetWriter(w, c, "$", "$") peerType := getPeerTypeFor(c, t, g.peerPackages) - didForward, didBackward := false, false - if isDirectlyConvertible(t, peerType, g.manualConversions) { - didForward = true - g.generateConversion(t, peerType, sw) - } - if isDirectlyConvertible(peerType, t, g.manualConversions) { - didBackward = true - g.generateConversion(peerType, t, sw) - } - if didForward != didBackward { - if didForward { - glog.Fatalf("Could only generate one direction of conversion for %v -> %v", t, peerType) - } else { - glog.Fatalf("Could only generate one direction of conversion for %v <- %v", t, peerType) - } - } - if !didForward && !didBackward { - // TODO: This should be fatal but we have at least 8 types that - // currently fail this. The right thing to do is to figure out why they - // can't be generated and mark those fields as - // +k8s:conversion-gen=false, and ONLY do manual conversions for those - // fields, with the manual Convert_...() calling autoConvert_...() - // first. - glog.Errorf("Warning: could not generate autoConvert functions for %v <-> %v", t, peerType) - } + sw := generator.NewSnippetWriter(w, c, "$", "$") + g.generateConversion(t, peerType, sw) + g.generateConversion(peerType, t, sw) return sw.Error() } @@ -578,8 +477,17 @@ func (g *genConversion) generateConversion(inType, outType *types.Type, sw *gene sw.Do("return nil\n", nil) sw.Do("}\n\n", nil) - // If there is no public manual Conversion method, generate it. - if _, ok := g.preexists(inType, outType); !ok { + if _, found := g.preexists(inType, outType); found { + // There is a public manual Conversion method: use it. + } else if skipped := g.skippedFields[inType]; len(skipped) != 0 { + // The inType had some fields we could not generate. + glog.Errorf("Warning: could not find nor generate a final Conversion function for %v -> %v", inType, outType) + glog.Errorf(" the following fields need manual conversion:") + for _, f := range skipped { + glog.Errorf(" - %v", f) + } + } else { + // Emit a public conversion function. sw.Do("func "+nameTmpl+"(in *$.inType|raw$, out *$.outType|raw$, s $.Scope|raw$) error {\n", args) sw.Do("return auto"+nameTmpl+"(in, out, s)\n", args) sw.Do("}\n\n", nil) @@ -590,6 +498,7 @@ func (g *genConversion) generateConversion(inType, outType *types.Type, sw *gene // at any nesting level. This makes the autogenerator easy to understand, and // the compiler shouldn't care. func (g *genConversion) generateFor(inType, outType *types.Type, sw *generator.SnippetWriter) { + glog.V(5).Infof("generating %v -> %v", inType, outType) var f func(*types.Type, *types.Type, *generator.SnippetWriter) switch inType.Kind { case types.Builtin: @@ -717,6 +626,7 @@ func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.Snip copied.Name = outMemberType.Name outMemberType = &copied } + args := map[string]interface{}{ "inType": inMemberType, "outType": outMemberType, @@ -730,6 +640,14 @@ func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.Snip sw.Do("}\n", nil) continue } + + // If we can't auto-convert, punt before we emit any code. + if inMemberType.Kind != outMemberType.Kind { + sw.Do("// WARNING: field '"+inMember.Name+"' requires manual conversion\n", nil) + g.skippedFields[inType] = append(g.skippedFields[inType], inMember.Name) + continue + } + switch inMemberType.Kind { case types.Builtin: if inMemberType == outMemberType { @@ -793,7 +711,7 @@ func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.Snip } func (g *genConversion) isDirectlyAssignable(inType, outType *types.Type) bool { - return inType == outType || areTypesAliased(inType, outType) + return unwrapAlias(inType) == unwrapAlias(outType) } func (g *genConversion) doPointer(inType, outType *types.Type, sw *generator.SnippetWriter) { diff --git a/federation/apis/core/v1/zz_generated.conversion.go b/federation/apis/core/v1/zz_generated.conversion.go new file mode 100644 index 00000000000..24cdcb382e5 --- /dev/null +++ b/federation/apis/core/v1/zz_generated.conversion.go @@ -0,0 +1,35 @@ +// +build !ignore_autogenerated + +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// This file was autogenerated by conversion-gen. Do not edit it manually! + +package v1 + +import ( + runtime "k8s.io/kubernetes/pkg/runtime" +) + +func init() { + SchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(scheme *runtime.Scheme) error { + return scheme.AddGeneratedConversionFuncs() +} diff --git a/pkg/apis/apps/v1alpha1/zz_generated.conversion.go b/pkg/apis/apps/v1alpha1/zz_generated.conversion.go index 767eff72862..c01ce9508c4 100644 --- a/pkg/apis/apps/v1alpha1/zz_generated.conversion.go +++ b/pkg/apis/apps/v1alpha1/zz_generated.conversion.go @@ -22,6 +22,7 @@ package v1alpha1 import ( api "k8s.io/kubernetes/pkg/api" + v1 "k8s.io/kubernetes/pkg/api/v1" apps "k8s.io/kubernetes/pkg/apis/apps" conversion "k8s.io/kubernetes/pkg/conversion" runtime "k8s.io/kubernetes/pkg/runtime" @@ -139,6 +140,50 @@ func Convert_apps_PetSetList_To_v1alpha1_PetSetList(in *apps.PetSetList, out *Pe return autoConvert_apps_PetSetList_To_v1alpha1_PetSetList(in, out, s) } +func autoConvert_v1alpha1_PetSetSpec_To_apps_PetSetSpec(in *PetSetSpec, out *apps.PetSetSpec, s conversion.Scope) error { + // WARNING: field 'Replicas' requires manual conversion + out.Selector = in.Selector + if err := v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(&in.Template, &out.Template, s); err != nil { + return err + } + if in.VolumeClaimTemplates != nil { + in, out := &in.VolumeClaimTemplates, &out.VolumeClaimTemplates + *out = make([]api.PersistentVolumeClaim, len(*in)) + for i := range *in { + // TODO: Inefficient conversion - can we improve it? + if err := s.Convert(&(*in)[i], &(*out)[i], 0); err != nil { + return err + } + } + } else { + out.VolumeClaimTemplates = nil + } + out.ServiceName = in.ServiceName + return nil +} + +func autoConvert_apps_PetSetSpec_To_v1alpha1_PetSetSpec(in *apps.PetSetSpec, out *PetSetSpec, s conversion.Scope) error { + // WARNING: field 'Replicas' requires manual conversion + out.Selector = in.Selector + if err := v1.Convert_api_PodTemplateSpec_To_v1_PodTemplateSpec(&in.Template, &out.Template, s); err != nil { + return err + } + if in.VolumeClaimTemplates != nil { + in, out := &in.VolumeClaimTemplates, &out.VolumeClaimTemplates + *out = make([]v1.PersistentVolumeClaim, len(*in)) + for i := range *in { + // TODO: Inefficient conversion - can we improve it? + if err := s.Convert(&(*in)[i], &(*out)[i], 0); err != nil { + return err + } + } + } else { + out.VolumeClaimTemplates = nil + } + out.ServiceName = in.ServiceName + return nil +} + func autoConvert_v1alpha1_PetSetStatus_To_apps_PetSetStatus(in *PetSetStatus, out *apps.PetSetStatus, s conversion.Scope) error { out.ObservedGeneration = in.ObservedGeneration out.Replicas = int(in.Replicas) diff --git a/pkg/apis/extensions/v1beta1/zz_generated.conversion.go b/pkg/apis/extensions/v1beta1/zz_generated.conversion.go index 70d33c1029c..9eac33030c5 100644 --- a/pkg/apis/extensions/v1beta1/zz_generated.conversion.go +++ b/pkg/apis/extensions/v1beta1/zz_generated.conversion.go @@ -941,6 +941,18 @@ func Convert_autoscaling_HorizontalPodAutoscalerList_To_v1beta1_HorizontalPodAut return autoConvert_autoscaling_HorizontalPodAutoscalerList_To_v1beta1_HorizontalPodAutoscalerList(in, out, s) } +func autoConvert_v1beta1_HorizontalPodAutoscalerSpec_To_autoscaling_HorizontalPodAutoscalerSpec(in *HorizontalPodAutoscalerSpec, out *autoscaling.HorizontalPodAutoscalerSpec, s conversion.Scope) error { + out.MinReplicas = in.MinReplicas + out.MaxReplicas = in.MaxReplicas + return nil +} + +func autoConvert_autoscaling_HorizontalPodAutoscalerSpec_To_v1beta1_HorizontalPodAutoscalerSpec(in *autoscaling.HorizontalPodAutoscalerSpec, out *HorizontalPodAutoscalerSpec, s conversion.Scope) error { + out.MinReplicas = in.MinReplicas + out.MaxReplicas = in.MaxReplicas + return nil +} + func autoConvert_v1beta1_HorizontalPodAutoscalerStatus_To_autoscaling_HorizontalPodAutoscalerStatus(in *HorizontalPodAutoscalerStatus, out *autoscaling.HorizontalPodAutoscalerStatus, s conversion.Scope) error { out.ObservedGeneration = in.ObservedGeneration out.LastScaleTime = in.LastScaleTime @@ -1432,6 +1444,44 @@ func Convert_batch_JobList_To_v1beta1_JobList(in *batch.JobList, out *JobList, s return autoConvert_batch_JobList_To_v1beta1_JobList(in, out, s) } +func autoConvert_v1beta1_JobSpec_To_batch_JobSpec(in *JobSpec, out *batch.JobSpec, s conversion.Scope) error { + out.Parallelism = in.Parallelism + out.Completions = in.Completions + out.ActiveDeadlineSeconds = in.ActiveDeadlineSeconds + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(unversioned.LabelSelector) + if err := Convert_v1beta1_LabelSelector_To_unversioned_LabelSelector(*in, *out, s); err != nil { + return err + } + } else { + out.Selector = nil + } + if err := v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(&in.Template, &out.Template, s); err != nil { + return err + } + return nil +} + +func autoConvert_batch_JobSpec_To_v1beta1_JobSpec(in *batch.JobSpec, out *JobSpec, s conversion.Scope) error { + out.Parallelism = in.Parallelism + out.Completions = in.Completions + out.ActiveDeadlineSeconds = in.ActiveDeadlineSeconds + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(LabelSelector) + if err := Convert_unversioned_LabelSelector_To_v1beta1_LabelSelector(*in, *out, s); err != nil { + return err + } + } else { + out.Selector = nil + } + if err := v1.Convert_api_PodTemplateSpec_To_v1_PodTemplateSpec(&in.Template, &out.Template, s); err != nil { + return err + } + return nil +} + func autoConvert_v1beta1_JobStatus_To_batch_JobStatus(in *JobStatus, out *batch.JobStatus, s conversion.Scope) error { if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions @@ -2282,6 +2332,18 @@ func Convert_extensions_RollbackConfig_To_v1beta1_RollbackConfig(in *extensions. return autoConvert_extensions_RollbackConfig_To_v1beta1_RollbackConfig(in, out, s) } +func autoConvert_v1beta1_RollingUpdateDeployment_To_extensions_RollingUpdateDeployment(in *RollingUpdateDeployment, out *extensions.RollingUpdateDeployment, s conversion.Scope) error { + // WARNING: field 'MaxUnavailable' requires manual conversion + // WARNING: field 'MaxSurge' requires manual conversion + return nil +} + +func autoConvert_extensions_RollingUpdateDeployment_To_v1beta1_RollingUpdateDeployment(in *extensions.RollingUpdateDeployment, out *RollingUpdateDeployment, s conversion.Scope) error { + // WARNING: field 'MaxUnavailable' requires manual conversion + // WARNING: field 'MaxSurge' requires manual conversion + return nil +} + func autoConvert_v1beta1_RunAsUserStrategyOptions_To_extensions_RunAsUserStrategyOptions(in *RunAsUserStrategyOptions, out *extensions.RunAsUserStrategyOptions, s conversion.Scope) error { out.Rule = extensions.RunAsUserStrategy(in.Rule) if in.Ranges != nil { @@ -2420,6 +2482,18 @@ func Convert_extensions_ScaleSpec_To_v1beta1_ScaleSpec(in *extensions.ScaleSpec, return autoConvert_extensions_ScaleSpec_To_v1beta1_ScaleSpec(in, out, s) } +func autoConvert_v1beta1_ScaleStatus_To_extensions_ScaleStatus(in *ScaleStatus, out *extensions.ScaleStatus, s conversion.Scope) error { + out.Replicas = in.Replicas + // WARNING: field 'Selector' requires manual conversion + return nil +} + +func autoConvert_extensions_ScaleStatus_To_v1beta1_ScaleStatus(in *extensions.ScaleStatus, out *ScaleStatus, s conversion.Scope) error { + out.Replicas = in.Replicas + // WARNING: field 'Selector' requires manual conversion + return nil +} + func autoConvert_v1beta1_SupplementalGroupsStrategyOptions_To_extensions_SupplementalGroupsStrategyOptions(in *SupplementalGroupsStrategyOptions, out *extensions.SupplementalGroupsStrategyOptions, s conversion.Scope) error { out.Rule = extensions.SupplementalGroupsStrategyType(in.Rule) if in.Ranges != nil { From 38d7c4b271ea50db4ba3748c00e75195259a5fe5 Mon Sep 17 00:00:00 2001 From: Tim Hockin Date: Mon, 26 Sep 2016 08:33:53 -0700 Subject: [PATCH 7/7] Conversion: log opted-out fields --- .../conversion-gen/generators/conversion.go | 12 ++++++++---- pkg/api/v1/zz_generated.conversion.go | 9 +++++++++ .../apps/v1alpha1/zz_generated.conversion.go | 4 ++-- .../v1beta1/zz_generated.conversion.go | 19 +++++++++++++------ 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/cmd/libs/go2idl/conversion-gen/generators/conversion.go b/cmd/libs/go2idl/conversion-gen/generators/conversion.go index 210f20725bb..f557f759fba 100644 --- a/cmd/libs/go2idl/conversion-gen/generators/conversion.go +++ b/cmd/libs/go2idl/conversion-gen/generators/conversion.go @@ -603,16 +603,19 @@ func (g *genConversion) doSlice(inType, outType *types.Type, sw *generator.Snipp func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.SnippetWriter) { for _, inMember := range inType.Members { - // Check if this member is excluded from conversion if tagvals := extractTag(inMember.CommentLines); tagvals != nil && tagvals[0] == "false" { + // This field is excluded from conversion. + sw.Do("// INFO: in."+inMember.Name+" opted out of conversion generation\n", nil) continue } outMember, found := findMember(outType, inMember.Name) if !found { - // Since this object wasn't filtered out, this means that - // this field has "+k8s:conversion-gen=false" comment to ignore it. + // This field doesn't exist in the peer. + sw.Do("// WARNING: in."+inMember.Name+" requires manual conversion: does not exist in peer-type\n", nil) + g.skippedFields[inType] = append(g.skippedFields[inType], inMember.Name) continue } + inMemberType, outMemberType := inMember.Type, outMember.Type // create a copy of both underlying types but give them the top level alias name (since aliases // are assignable) @@ -643,7 +646,8 @@ func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.Snip // If we can't auto-convert, punt before we emit any code. if inMemberType.Kind != outMemberType.Kind { - sw.Do("// WARNING: field '"+inMember.Name+"' requires manual conversion\n", nil) + sw.Do("// WARNING: in."+inMember.Name+" requires manual conversion: inconvertible types ("+ + inMemberType.String()+" vs "+outMemberType.String()+")\n", nil) g.skippedFields[inType] = append(g.skippedFields[inType], inMember.Name) continue } diff --git a/pkg/api/v1/zz_generated.conversion.go b/pkg/api/v1/zz_generated.conversion.go index 2f5acd0940f..f2f663746b7 100644 --- a/pkg/api/v1/zz_generated.conversion.go +++ b/pkg/api/v1/zz_generated.conversion.go @@ -4926,6 +4926,9 @@ func autoConvert_v1_PodSecurityContext_To_api_PodSecurityContext(in *PodSecurity } func autoConvert_api_PodSecurityContext_To_v1_PodSecurityContext(in *api.PodSecurityContext, out *PodSecurityContext, s conversion.Scope) error { + // INFO: in.HostNetwork opted out of conversion generation + // INFO: in.HostPID opted out of conversion generation + // INFO: in.HostIPC opted out of conversion generation if in.SELinuxOptions != nil { in, out := &in.SELinuxOptions, &out.SELinuxOptions *out = new(SELinuxOptions) @@ -5017,7 +5020,11 @@ func autoConvert_v1_PodSpec_To_api_PodSpec(in *PodSpec, out *api.PodSpec, s conv out.DNSPolicy = api.DNSPolicy(in.DNSPolicy) out.NodeSelector = in.NodeSelector out.ServiceAccountName = in.ServiceAccountName + // INFO: in.DeprecatedServiceAccount opted out of conversion generation out.NodeName = in.NodeName + // INFO: in.HostNetwork opted out of conversion generation + // INFO: in.HostPID opted out of conversion generation + // INFO: in.HostIPC opted out of conversion generation if in.SecurityContext != nil { in, out := &in.SecurityContext, &out.SecurityContext *out = new(api.PodSecurityContext) @@ -5995,6 +6002,7 @@ func autoConvert_v1_Secret_To_api_Secret(in *Secret, out *api.Secret, s conversi return err } out.Data = in.Data + // INFO: in.StringData opted out of conversion generation out.Type = api.SecretType(in.Type) return nil } @@ -6503,6 +6511,7 @@ func autoConvert_v1_ServiceSpec_To_api_ServiceSpec(in *ServiceSpec, out *api.Ser out.ClusterIP = in.ClusterIP out.Type = api.ServiceType(in.Type) out.ExternalIPs = in.ExternalIPs + // INFO: in.DeprecatedPublicIPs opted out of conversion generation out.SessionAffinity = api.ServiceAffinity(in.SessionAffinity) out.LoadBalancerIP = in.LoadBalancerIP out.LoadBalancerSourceRanges = in.LoadBalancerSourceRanges diff --git a/pkg/apis/apps/v1alpha1/zz_generated.conversion.go b/pkg/apis/apps/v1alpha1/zz_generated.conversion.go index c01ce9508c4..4c07d5878ae 100644 --- a/pkg/apis/apps/v1alpha1/zz_generated.conversion.go +++ b/pkg/apis/apps/v1alpha1/zz_generated.conversion.go @@ -141,7 +141,7 @@ func Convert_apps_PetSetList_To_v1alpha1_PetSetList(in *apps.PetSetList, out *Pe } func autoConvert_v1alpha1_PetSetSpec_To_apps_PetSetSpec(in *PetSetSpec, out *apps.PetSetSpec, s conversion.Scope) error { - // WARNING: field 'Replicas' requires manual conversion + // WARNING: in.Replicas requires manual conversion: inconvertible types (*int32 vs int) out.Selector = in.Selector if err := v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(&in.Template, &out.Template, s); err != nil { return err @@ -163,7 +163,7 @@ func autoConvert_v1alpha1_PetSetSpec_To_apps_PetSetSpec(in *PetSetSpec, out *app } func autoConvert_apps_PetSetSpec_To_v1alpha1_PetSetSpec(in *apps.PetSetSpec, out *PetSetSpec, s conversion.Scope) error { - // WARNING: field 'Replicas' requires manual conversion + // WARNING: in.Replicas requires manual conversion: inconvertible types (int vs *int32) out.Selector = in.Selector if err := v1.Convert_api_PodTemplateSpec_To_v1_PodTemplateSpec(&in.Template, &out.Template, s); err != nil { return err diff --git a/pkg/apis/extensions/v1beta1/zz_generated.conversion.go b/pkg/apis/extensions/v1beta1/zz_generated.conversion.go index 9eac33030c5..22a50b3c69e 100644 --- a/pkg/apis/extensions/v1beta1/zz_generated.conversion.go +++ b/pkg/apis/extensions/v1beta1/zz_generated.conversion.go @@ -942,14 +942,18 @@ func Convert_autoscaling_HorizontalPodAutoscalerList_To_v1beta1_HorizontalPodAut } func autoConvert_v1beta1_HorizontalPodAutoscalerSpec_To_autoscaling_HorizontalPodAutoscalerSpec(in *HorizontalPodAutoscalerSpec, out *autoscaling.HorizontalPodAutoscalerSpec, s conversion.Scope) error { + // WARNING: in.ScaleRef requires manual conversion: does not exist in peer-type out.MinReplicas = in.MinReplicas out.MaxReplicas = in.MaxReplicas + // WARNING: in.CPUUtilization requires manual conversion: does not exist in peer-type return nil } func autoConvert_autoscaling_HorizontalPodAutoscalerSpec_To_v1beta1_HorizontalPodAutoscalerSpec(in *autoscaling.HorizontalPodAutoscalerSpec, out *HorizontalPodAutoscalerSpec, s conversion.Scope) error { + // WARNING: in.ScaleTargetRef requires manual conversion: does not exist in peer-type out.MinReplicas = in.MinReplicas out.MaxReplicas = in.MaxReplicas + // WARNING: in.TargetCPUUtilizationPercentage requires manual conversion: does not exist in peer-type return nil } @@ -1457,6 +1461,7 @@ func autoConvert_v1beta1_JobSpec_To_batch_JobSpec(in *JobSpec, out *batch.JobSpe } else { out.Selector = nil } + // WARNING: in.AutoSelector requires manual conversion: does not exist in peer-type if err := v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(&in.Template, &out.Template, s); err != nil { return err } @@ -1476,6 +1481,7 @@ func autoConvert_batch_JobSpec_To_v1beta1_JobSpec(in *batch.JobSpec, out *JobSpe } else { out.Selector = nil } + // WARNING: in.ManualSelector requires manual conversion: does not exist in peer-type if err := v1.Convert_api_PodTemplateSpec_To_v1_PodTemplateSpec(&in.Template, &out.Template, s); err != nil { return err } @@ -2333,14 +2339,14 @@ func Convert_extensions_RollbackConfig_To_v1beta1_RollbackConfig(in *extensions. } func autoConvert_v1beta1_RollingUpdateDeployment_To_extensions_RollingUpdateDeployment(in *RollingUpdateDeployment, out *extensions.RollingUpdateDeployment, s conversion.Scope) error { - // WARNING: field 'MaxUnavailable' requires manual conversion - // WARNING: field 'MaxSurge' requires manual conversion + // WARNING: in.MaxUnavailable requires manual conversion: inconvertible types (*k8s.io/kubernetes/pkg/util/intstr.IntOrString vs k8s.io/kubernetes/pkg/util/intstr.IntOrString) + // WARNING: in.MaxSurge requires manual conversion: inconvertible types (*k8s.io/kubernetes/pkg/util/intstr.IntOrString vs k8s.io/kubernetes/pkg/util/intstr.IntOrString) return nil } func autoConvert_extensions_RollingUpdateDeployment_To_v1beta1_RollingUpdateDeployment(in *extensions.RollingUpdateDeployment, out *RollingUpdateDeployment, s conversion.Scope) error { - // WARNING: field 'MaxUnavailable' requires manual conversion - // WARNING: field 'MaxSurge' requires manual conversion + // WARNING: in.MaxUnavailable requires manual conversion: inconvertible types (k8s.io/kubernetes/pkg/util/intstr.IntOrString vs *k8s.io/kubernetes/pkg/util/intstr.IntOrString) + // WARNING: in.MaxSurge requires manual conversion: inconvertible types (k8s.io/kubernetes/pkg/util/intstr.IntOrString vs *k8s.io/kubernetes/pkg/util/intstr.IntOrString) return nil } @@ -2484,13 +2490,14 @@ func Convert_extensions_ScaleSpec_To_v1beta1_ScaleSpec(in *extensions.ScaleSpec, func autoConvert_v1beta1_ScaleStatus_To_extensions_ScaleStatus(in *ScaleStatus, out *extensions.ScaleStatus, s conversion.Scope) error { out.Replicas = in.Replicas - // WARNING: field 'Selector' requires manual conversion + // WARNING: in.Selector requires manual conversion: inconvertible types (map[string]string vs *k8s.io/kubernetes/pkg/api/unversioned.LabelSelector) + // WARNING: in.TargetSelector requires manual conversion: does not exist in peer-type return nil } func autoConvert_extensions_ScaleStatus_To_v1beta1_ScaleStatus(in *extensions.ScaleStatus, out *ScaleStatus, s conversion.Scope) error { out.Replicas = in.Replicas - // WARNING: field 'Selector' requires manual conversion + // WARNING: in.Selector requires manual conversion: inconvertible types (*k8s.io/kubernetes/pkg/api/unversioned.LabelSelector vs map[string]string) return nil }