Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
8eca7629
Commit
8eca7629
authored
Apr 17, 2015
by
Wojciech Tyczynski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improvements to conversions generator.
parent
7dcce2ee
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
119 additions
and
40 deletions
+119
-40
conversion.go
cmd/kube-conversion/conversion.go
+33
-22
api_changes.md
docs/devel/api_changes.md
+17
-2
generator.go
pkg/conversion/generator.go
+69
-16
No files found.
cmd/kube-conversion/conversion.go
View file @
8eca7629
...
@@ -20,7 +20,6 @@ import (
...
@@ -20,7 +20,6 @@ import (
"io"
"io"
"os"
"os"
"runtime"
"runtime"
"strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
_
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
_
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
...
@@ -33,39 +32,51 @@ import (
...
@@ -33,39 +32,51 @@ import (
)
)
var
(
var
(
outputDest
=
flag
.
StringP
(
"output"
,
"o"
,
"-"
,
"Output destination; '-' means stdout"
)
functionDest
=
flag
.
StringP
(
"funcDest"
,
"f"
,
"-"
,
"Output for conversion functions; '-' means stdout"
)
versions
=
flag
.
StringP
(
"versions"
,
"v"
,
"v1beta3"
,
"Comma separated list of versions for conversion."
)
namesDest
=
flag
.
StringP
(
"nameDest"
,
"n"
,
"-"
,
"Output for function names; '-' means stdout"
)
version
=
flag
.
StringP
(
"version"
,
"v"
,
"v1beta3"
,
"Version for conversion."
)
)
)
func
main
()
{
func
main
()
{
runtime
.
GOMAXPROCS
(
runtime
.
NumCPU
())
runtime
.
GOMAXPROCS
(
runtime
.
NumCPU
())
flag
.
Parse
()
flag
.
Parse
()
var
o
ut
io
.
Writer
var
funcO
ut
io
.
Writer
if
*
output
Dest
==
"-"
{
if
*
function
Dest
==
"-"
{
o
ut
=
os
.
Stdout
funcO
ut
=
os
.
Stdout
}
else
{
}
else
{
file
,
err
:=
os
.
Create
(
*
output
Dest
)
file
,
err
:=
os
.
Create
(
*
function
Dest
)
if
err
!=
nil
{
if
err
!=
nil
{
glog
.
Fatalf
(
"Couldn't open %v: %v"
,
*
output
Dest
,
err
)
glog
.
Fatalf
(
"Couldn't open %v: %v"
,
*
function
Dest
,
err
)
}
}
defer
file
.
Close
()
defer
file
.
Close
()
o
ut
=
file
funcO
ut
=
file
}
}
var
nameOut
io
.
Writer
versionsForConversion
:=
strings
.
Split
(
*
versions
,
","
)
if
*
namesDest
==
"-"
{
for
_
,
version
:=
range
versionsForConversion
{
nameOut
=
os
.
Stdout
generator
:=
conversion
.
NewGenerator
(
api
.
Scheme
.
Raw
())
}
else
{
// TODO(wojtek-t): Change the overwrites to a flag.
file
,
err
:=
os
.
Create
(
*
namesDest
)
generator
.
OverwritePackage
(
version
,
""
)
if
err
!=
nil
{
generator
.
OverwritePackage
(
"api"
,
"newer"
)
glog
.
Fatalf
(
"Couldn't open %v: %v"
,
*
functionDest
,
err
)
for
_
,
knownType
:=
range
api
.
Scheme
.
KnownTypes
(
version
)
{
if
err
:=
generator
.
GenerateConversionsForType
(
version
,
knownType
);
err
!=
nil
{
glog
.
Errorf
(
"error while generating conversion functions for %v: %v"
,
knownType
,
err
)
}
}
}
if
err
:=
generator
.
WriteConversionFunctions
(
out
);
err
!=
nil
{
defer
file
.
Close
()
glog
.
Fatalf
(
"Error while writing conversion functions: %v"
,
err
)
nameOut
=
file
}
generator
:=
conversion
.
NewGenerator
(
api
.
Scheme
.
Raw
())
// TODO(wojtek-t): Change the overwrites to a flag.
generator
.
OverwritePackage
(
*
version
,
""
)
generator
.
OverwritePackage
(
"api"
,
"newer"
)
for
_
,
knownType
:=
range
api
.
Scheme
.
KnownTypes
(
*
version
)
{
if
err
:=
generator
.
GenerateConversionsForType
(
*
version
,
knownType
);
err
!=
nil
{
glog
.
Errorf
(
"error while generating conversion functions for %v: %v"
,
knownType
,
err
)
}
}
}
}
if
err
:=
generator
.
WriteConversionFunctions
(
funcOut
);
err
!=
nil
{
glog
.
Fatalf
(
"Error while writing conversion functions: %v"
,
err
)
}
if
err
:=
generator
.
WriteConversionFunctionNames
(
nameOut
);
err
!=
nil
{
glog
.
Fatalf
(
"Error while writing conversion functions: %v"
,
err
)
}
}
}
docs/devel/api_changes.md
View file @
8eca7629
...
@@ -222,9 +222,24 @@ types, structural change in particular - you must add some logic to convert
...
@@ -222,9 +222,24 @@ types, structural change in particular - you must add some logic to convert
versioned APIs to and from the internal representation. If you see errors from
versioned APIs to and from the internal representation. If you see errors from
the
`serialization_test`
, it may indicate the need for explicit conversions.
the
`serialization_test`
, it may indicate the need for explicit conversions.
Performance of conversions very heavily influence performance of apiserver.
Thus, we are auto-generating conversion functions that are much more efficient
than the generic ones (which are based on reflections and thus are highly
inefficient).
The conversion code resides with each versioned API -
The conversion code resides with each versioned API -
`pkg/api/<version>/conversion.go`
. Unsurprisingly, this also requires you to
`pkg/api/<version>/conversion.go`
. To regenerate conversion functions:
add tests to
`pkg/api/<version>/conversion_test.go`
.
-
run
```
$ go run cmd/kube-conversion/conversion.go -v <version> -f <file1.txt> -n <file2.txt>
```
-
replace all conversion functions (convert
\*
functions) in the above file
with the contents of
\<
file1.txt
\>
-
replace arguments of
`newer.Scheme.AddGeneratedConversionFuncs`
with the contents of
\<
file2.txt
\>
Unsurprisingly, this also requires you to add tests to
`pkg/api/<version>/conversion_test.go`
.
## Update the fuzzer
## Update the fuzzer
...
...
pkg/conversion/generator.go
View file @
8eca7629
...
@@ -27,6 +27,7 @@ import (
...
@@ -27,6 +27,7 @@ import (
type
Generator
interface
{
type
Generator
interface
{
GenerateConversionsForType
(
version
string
,
reflection
reflect
.
Type
)
error
GenerateConversionsForType
(
version
string
,
reflection
reflect
.
Type
)
error
WriteConversionFunctions
(
w
io
.
Writer
)
error
WriteConversionFunctions
(
w
io
.
Writer
)
error
WriteConversionFunctionNames
(
w
io
.
Writer
)
error
OverwritePackage
(
pkg
,
overwrite
string
)
OverwritePackage
(
pkg
,
overwrite
string
)
}
}
...
@@ -177,7 +178,7 @@ func (g *generator) WriteConversionFunctions(w io.Writer) error {
...
@@ -177,7 +178,7 @@ func (g *generator) WriteConversionFunctions(w io.Writer) error {
}
}
sort
.
Sort
(
byName
(
keys
))
sort
.
Sort
(
byName
(
keys
))
indent
:=
2
indent
:=
0
for
_
,
inType
:=
range
keys
{
for
_
,
inType
:=
range
keys
{
outType
:=
g
.
convertibles
[
inType
]
outType
:=
g
.
convertibles
[
inType
]
// All types in g.convertibles are structs.
// All types in g.convertibles are structs.
...
@@ -194,12 +195,32 @@ func (g *generator) WriteConversionFunctions(w io.Writer) error {
...
@@ -194,12 +195,32 @@ func (g *generator) WriteConversionFunctions(w io.Writer) error {
return
nil
return
nil
}
}
func
(
g
*
generator
)
WriteConversionFunctionNames
(
w
io
.
Writer
)
error
{
// Write conversion function names alphabetically ordered.
var
names
[]
string
for
inType
,
outType
:=
range
g
.
convertibles
{
names
=
append
(
names
,
conversionFunctionName
(
inType
,
outType
))
names
=
append
(
names
,
conversionFunctionName
(
outType
,
inType
))
}
sort
.
Strings
(
names
)
indent
:=
2
for
_
,
name
:=
range
names
{
if
err
:=
writeLine
(
w
,
indent
,
fmt
.
Sprintf
(
"%s,
\n
"
,
name
));
err
!=
nil
{
return
err
}
}
return
nil
}
func
(
g
*
generator
)
typeName
(
inType
reflect
.
Type
)
string
{
func
(
g
*
generator
)
typeName
(
inType
reflect
.
Type
)
string
{
switch
inType
.
Kind
()
{
switch
inType
.
Kind
()
{
case
reflect
.
Map
:
case
reflect
.
Map
:
return
fmt
.
Sprintf
(
"map[%s]%s"
,
g
.
typeName
(
inType
.
Key
()),
g
.
typeName
(
inType
.
Elem
()))
return
fmt
.
Sprintf
(
"map[%s]%s"
,
g
.
typeName
(
inType
.
Key
()),
g
.
typeName
(
inType
.
Elem
()))
case
reflect
.
Slice
:
case
reflect
.
Slice
:
return
fmt
.
Sprintf
(
"[]%s"
,
g
.
typeName
(
inType
.
Elem
()))
return
fmt
.
Sprintf
(
"[]%s"
,
g
.
typeName
(
inType
.
Elem
()))
case
reflect
.
Ptr
:
return
fmt
.
Sprintf
(
"*%s"
,
g
.
typeName
(
inType
.
Elem
()))
default
:
default
:
typeWithPkg
:=
fmt
.
Sprintf
(
"%s"
,
inType
)
typeWithPkg
:=
fmt
.
Sprintf
(
"%s"
,
inType
)
slices
:=
strings
.
Split
(
typeWithPkg
,
"."
)
slices
:=
strings
.
Split
(
typeWithPkg
,
"."
)
...
@@ -221,6 +242,22 @@ func (g *generator) typeName(inType reflect.Type) string {
...
@@ -221,6 +242,22 @@ func (g *generator) typeName(inType reflect.Type) string {
}
}
}
}
func
packageForName
(
inType
reflect
.
Type
)
string
{
if
inType
.
PkgPath
()
==
""
{
return
""
}
slices
:=
strings
.
Split
(
inType
.
PkgPath
(),
"/"
)
return
slices
[
len
(
slices
)
-
1
]
}
func
conversionFunctionName
(
inType
,
outType
reflect
.
Type
)
string
{
funcNameFormat
:=
"convert_%s_%s_To_%s_%s"
inPkg
:=
packageForName
(
inType
)
outPkg
:=
packageForName
(
outType
)
funcName
:=
fmt
.
Sprintf
(
funcNameFormat
,
inPkg
,
inType
.
Name
(),
outPkg
,
outType
.
Name
())
return
funcName
}
func
indentLine
(
w
io
.
Writer
,
indent
int
)
error
{
func
indentLine
(
w
io
.
Writer
,
indent
int
)
error
{
indentation
:=
""
indentation
:=
""
for
i
:=
0
;
i
<
indent
;
i
++
{
for
i
:=
0
;
i
<
indent
;
i
++
{
...
@@ -240,9 +277,9 @@ func writeLine(w io.Writer, indent int, line string) error {
...
@@ -240,9 +277,9 @@ func writeLine(w io.Writer, indent int, line string) error {
return
nil
return
nil
}
}
func
writeHeader
(
w
io
.
Writer
,
inType
,
outType
string
,
indent
int
)
error
{
func
writeHeader
(
w
io
.
Writer
,
name
,
inType
,
outType
string
,
indent
int
)
error
{
format
:=
"func(in *%s, out *%s, s conversion.Scope) error {
\n
"
format
:=
"func
%s
(in *%s, out *%s, s conversion.Scope) error {
\n
"
stmt
:=
fmt
.
Sprintf
(
format
,
inType
,
outType
)
stmt
:=
fmt
.
Sprintf
(
format
,
name
,
inType
,
outType
)
return
writeLine
(
w
,
indent
,
stmt
)
return
writeLine
(
w
,
indent
,
stmt
)
}
}
...
@@ -250,7 +287,7 @@ func writeFooter(w io.Writer, indent int) error {
...
@@ -250,7 +287,7 @@ func writeFooter(w io.Writer, indent int) error {
if
err
:=
writeLine
(
w
,
indent
+
1
,
"return nil
\n
"
);
err
!=
nil
{
if
err
:=
writeLine
(
w
,
indent
+
1
,
"return nil
\n
"
);
err
!=
nil
{
return
err
return
err
}
}
if
err
:=
writeLine
(
w
,
indent
,
"}
,
\n
"
);
err
!=
nil
{
if
err
:=
writeLine
(
w
,
indent
,
"}
\n
"
);
err
!=
nil
{
return
err
return
err
}
}
return
nil
return
nil
...
@@ -336,13 +373,29 @@ func (g *generator) writeConversionForSlice(w io.Writer, inField, outField refle
...
@@ -336,13 +373,29 @@ func (g *generator) writeConversionForSlice(w io.Writer, inField, outField refle
if
err
:=
writeLine
(
w
,
indent
+
1
,
forStmt
);
err
!=
nil
{
if
err
:=
writeLine
(
w
,
indent
+
1
,
forStmt
);
err
!=
nil
{
return
err
return
err
}
}
if
inField
.
Type
.
Elem
()
.
AssignableTo
(
outField
.
Type
.
Elem
())
{
assigned
:=
false
assignFormat
:=
"out.%s[i] = in.%s[i]
\n
"
switch
inField
.
Type
.
Elem
()
.
Kind
()
{
assignStmt
:=
fmt
.
Sprintf
(
assignFormat
,
outField
.
Name
,
inField
.
Name
)
case
reflect
.
Map
,
reflect
.
Ptr
,
reflect
.
Slice
,
reflect
.
Interface
,
reflect
.
Struct
:
if
err
:=
writeLine
(
w
,
indent
+
2
,
assignStmt
);
err
!=
nil
{
// Don't copy these via assignment/conversion!
return
err
default
:
// This should handle all simple types.
if
inField
.
Type
.
Elem
()
.
AssignableTo
(
outField
.
Type
.
Elem
())
{
assignFormat
:=
"out.%s[i] = in.%s[i]
\n
"
assignStmt
:=
fmt
.
Sprintf
(
assignFormat
,
outField
.
Name
,
inField
.
Name
)
if
err
:=
writeLine
(
w
,
indent
+
2
,
assignStmt
);
err
!=
nil
{
return
err
}
assigned
=
true
}
else
if
inField
.
Type
.
Elem
()
.
ConvertibleTo
(
outField
.
Type
.
Elem
())
{
assignFormat
:=
"out.%s[i] = %s(in.%s[i])
\n
"
assignStmt
:=
fmt
.
Sprintf
(
assignFormat
,
outField
.
Name
,
g
.
typeName
(
outField
.
Type
.
Elem
()),
inField
.
Name
)
if
err
:=
writeLine
(
w
,
indent
+
2
,
assignStmt
);
err
!=
nil
{
return
err
}
assigned
=
true
}
}
}
else
{
}
if
!
assigned
{
assignFormat
:=
"if err := s.Convert(&in.%s[i], &out.%s[i], 0); err != nil {
\n
"
assignFormat
:=
"if err := s.Convert(&in.%s[i], &out.%s[i], 0); err != nil {
\n
"
assignStmt
:=
fmt
.
Sprintf
(
assignFormat
,
inField
.
Name
,
outField
.
Name
)
assignStmt
:=
fmt
.
Sprintf
(
assignFormat
,
inField
.
Name
,
outField
.
Name
)
if
err
:=
writeLine
(
w
,
indent
+
2
,
assignStmt
);
err
!=
nil
{
if
err
:=
writeLine
(
w
,
indent
+
2
,
assignStmt
);
err
!=
nil
{
...
@@ -471,10 +524,6 @@ func (g *generator) writeConversionForStruct(w io.Writer, inType, outType reflec
...
@@ -471,10 +524,6 @@ func (g *generator) writeConversionForStruct(w io.Writer, inType, outType reflec
continue
continue
}
}
// TODO(wojtek-t): At some point we may consider named functions and call
// appropriate function here instead of using generic Convert method that
// will call the same method underneath after some additional operations.
assignFormat
:=
"if err := s.Convert(&in.%s, &out.%s, 0); err != nil {
\n
"
assignFormat
:=
"if err := s.Convert(&in.%s, &out.%s, 0); err != nil {
\n
"
assignStmt
:=
fmt
.
Sprintf
(
assignFormat
,
inField
.
Name
,
outField
.
Name
)
assignStmt
:=
fmt
.
Sprintf
(
assignFormat
,
inField
.
Name
,
outField
.
Name
)
if
err
:=
writeLine
(
w
,
indent
,
assignStmt
);
err
!=
nil
{
if
err
:=
writeLine
(
w
,
indent
,
assignStmt
);
err
!=
nil
{
...
@@ -491,7 +540,8 @@ func (g *generator) writeConversionForStruct(w io.Writer, inType, outType reflec
...
@@ -491,7 +540,8 @@ func (g *generator) writeConversionForStruct(w io.Writer, inType, outType reflec
}
}
func
(
g
*
generator
)
writeConversionForType
(
w
io
.
Writer
,
inType
,
outType
reflect
.
Type
,
indent
int
)
error
{
func
(
g
*
generator
)
writeConversionForType
(
w
io
.
Writer
,
inType
,
outType
reflect
.
Type
,
indent
int
)
error
{
if
err
:=
writeHeader
(
w
,
g
.
typeName
(
inType
),
g
.
typeName
(
outType
),
indent
);
err
!=
nil
{
funcName
:=
conversionFunctionName
(
inType
,
outType
)
if
err
:=
writeHeader
(
w
,
funcName
,
g
.
typeName
(
inType
),
g
.
typeName
(
outType
),
indent
);
err
!=
nil
{
return
err
return
err
}
}
switch
inType
.
Kind
()
{
switch
inType
.
Kind
()
{
...
@@ -505,6 +555,9 @@ func (g *generator) writeConversionForType(w io.Writer, inType, outType reflect.
...
@@ -505,6 +555,9 @@ func (g *generator) writeConversionForType(w io.Writer, inType, outType reflect.
if
err
:=
writeFooter
(
w
,
indent
);
err
!=
nil
{
if
err
:=
writeFooter
(
w
,
indent
);
err
!=
nil
{
return
err
return
err
}
}
if
err
:=
writeLine
(
w
,
0
,
"
\n
"
);
err
!=
nil
{
return
err
}
return
nil
return
nil
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment