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
1ddb68d8
Commit
1ddb68d8
authored
Nov 23, 2014
by
Tim Hockin
Committed by
Yu-Ju Hong
Feb 02, 2015
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Sketch: a third take on defaulting values
parent
2ac6bbb7
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
164 additions
and
24 deletions
+164
-24
defaults.go
pkg/api/v1beta1/defaults.go
+61
-0
converter.go
pkg/conversion/converter.go
+62
-14
converter_test.go
pkg/conversion/converter_test.go
+7
-7
scheme.go
pkg/conversion/scheme.go
+25
-2
scheme.go
pkg/runtime/scheme.go
+9
-1
No files found.
pkg/api/v1beta1/defaults.go
0 → 100644
View file @
1ddb68d8
/*
Copyright 2014 Google Inc. All rights reserved.
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.
*/
package
v1beta1
import
(
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
func
init
()
{
api
.
Scheme
.
AddDefaultingFuncs
(
func
(
obj
*
Volume
)
{
if
obj
.
Source
==
nil
||
util
.
AllPtrFieldsNil
(
obj
.
Source
)
{
obj
.
Source
=
&
VolumeSource
{
EmptyDir
:
&
EmptyDir
{},
}
}
},
func
(
obj
*
Port
)
{
if
obj
.
Protocol
==
""
{
obj
.
Protocol
=
ProtocolTCP
}
},
func
(
obj
*
Container
)
{
// TODO: delete helper functions that touch this
if
obj
.
ImagePullPolicy
==
""
{
obj
.
ImagePullPolicy
=
PullIfNotPresent
}
if
obj
.
TerminationMessagePath
==
""
{
// TODO: fix other code that sets this
obj
.
TerminationMessagePath
=
api
.
TerminationMessagePathDefault
}
},
func
(
obj
*
RestartPolicy
)
{
if
util
.
AllPtrFieldsNil
(
obj
)
{
obj
.
Always
=
&
RestartPolicyAlways
{}
}
},
func
(
obj
*
Service
)
{
if
obj
.
Protocol
==
""
{
obj
.
Protocol
=
ProtocolTCP
}
},
)
}
// TODO: remove redundant code in validation and conversion
pkg/conversion/converter.go
View file @
1ddb68d8
...
...
@@ -40,7 +40,7 @@ type DebugLogger interface {
type
Converter
struct
{
// Map from the conversion pair to a function which can
// do the conversion.
f
uncs
map
[
typePair
]
reflect
.
Value
conversionF
uncs
map
[
typePair
]
reflect
.
Value
// This is a map from a source field type and name, to a list of destination
// field type and name.
...
...
@@ -51,20 +51,25 @@ type Converter struct {
// source field name and type to look for.
structFieldSources
map
[
typeNamePair
][]
typeNamePair
// Map from a type to a function which applies defaults.
defaultingFuncs
map
[
reflect
.
Type
]
reflect
.
Value
// If non-nil, will be called to print helpful debugging info. Quite verbose.
Debug
DebugLogger
//
N
ameFunc is called to retrieve the name of a type; this name is used for the
//
n
ameFunc is called to retrieve the name of a type; this name is used for the
// purpose of deciding whether two types match or not (i.e., will we attempt to
// do a conversion). The default returns the go type name.
N
ameFunc
func
(
t
reflect
.
Type
)
string
n
ameFunc
func
(
t
reflect
.
Type
)
string
}
// NewConverter creates a new Converter object.
func
NewConverter
()
*
Converter
{
return
&
Converter
{
conversionFuncs
:
map
[
typePair
]
reflect
.
Value
{},
defaultingFuncs
:
map
[
reflect
.
Type
]
reflect
.
Value
{},
funcs
:
map
[
typePair
]
reflect
.
Value
{},
N
ameFunc
:
func
(
t
reflect
.
Type
)
string
{
return
t
.
Name
()
},
n
ameFunc
:
func
(
t
reflect
.
Type
)
string
{
return
t
.
Name
()
},
structFieldDests
:
map
[
typeNamePair
][]
typeNamePair
{},
structFieldSources
:
map
[
typeNamePair
][]
typeNamePair
{},
}
...
...
@@ -210,14 +215,18 @@ func (s *scope) error(message string, args ...interface{}) error {
return
fmt
.
Errorf
(
where
+
message
,
args
...
)
}
// Register
registers a conversion func with the Converter. conversionFunc must tak
e
//
three parameters: a pointer to the input type, a pointer to the output type, and
//
a conversion.Scope (which should be used if recursive conversion calls are desired).
// It must return an error.
// Register
ConversionFunc registers a conversion func with th
e
//
Converter. conversionFunc must take three parameters: a pointer to the input
//
type, a pointer to the output type, and a conversion.Scope (which should be
//
used if recursive conversion calls are desired).
It must return an error.
//
// Example:
// c.Register(func(in *Pod, out *v1beta1.Pod, s Scope) error { ... return nil })
func
(
c
*
Converter
)
Register
(
conversionFunc
interface
{})
error
{
// c.RegisteConversionFuncr(
// func(in *Pod, out *v1beta1.Pod, s Scope) error {
// // conversion logic...
// return nil
// })
func
(
c
*
Converter
)
RegisterConversionFunc
(
conversionFunc
interface
{})
error
{
fv
:=
reflect
.
ValueOf
(
conversionFunc
)
ft
:=
fv
.
Type
()
if
ft
.
Kind
()
!=
reflect
.
Func
{
...
...
@@ -246,7 +255,7 @@ func (c *Converter) Register(conversionFunc interface{}) error {
if
ft
.
Out
(
0
)
!=
errorType
{
return
fmt
.
Errorf
(
"expected error return, got: %v"
,
ft
)
}
c
.
f
uncs
[
typePair
{
ft
.
In
(
0
)
.
Elem
(),
ft
.
In
(
1
)
.
Elem
()}]
=
fv
c
.
conversionF
uncs
[
typePair
{
ft
.
In
(
0
)
.
Elem
(),
ft
.
In
(
1
)
.
Elem
()}]
=
fv
return
nil
}
...
...
@@ -266,6 +275,33 @@ func (c *Converter) SetStructFieldCopy(srcFieldType interface{}, srcFieldName st
return
nil
}
// RegisterDefaultingFunc registers a value-defaulting func with the Converter.
// defaultingFunc must take one parameters: a pointer to the input type.
//
// Example:
// c.RegisteDefaultingFuncr(
// func(in *v1beta1.Pod) {
// // defaulting logic...
// })
func
(
c
*
Converter
)
RegisterDefaultingFunc
(
defaultingFunc
interface
{})
error
{
fv
:=
reflect
.
ValueOf
(
defaultingFunc
)
ft
:=
fv
.
Type
()
if
ft
.
Kind
()
!=
reflect
.
Func
{
return
fmt
.
Errorf
(
"expected func, got: %v"
,
ft
)
}
if
ft
.
NumIn
()
!=
1
{
return
fmt
.
Errorf
(
"expected one 'in' param, got: %v"
,
ft
)
}
if
ft
.
NumOut
()
!=
0
{
return
fmt
.
Errorf
(
"expected zero 'out' params, got: %v"
,
ft
)
}
if
ft
.
In
(
0
)
.
Kind
()
!=
reflect
.
Ptr
{
return
fmt
.
Errorf
(
"expected pointer arg for 'in' param 0, got: %v"
,
ft
)
}
c
.
defaultingFuncs
[
ft
.
In
(
0
)
.
Elem
()]
=
fv
return
nil
}
// FieldMatchingFlags contains a list of ways in which struct fields could be
// copied. These constants may be | combined.
type
FieldMatchingFlags
int
...
...
@@ -379,7 +415,18 @@ func (c *Converter) callCustom(sv, dv, custom reflect.Value, scope *scope) error
// one is registered.
func
(
c
*
Converter
)
convert
(
sv
,
dv
reflect
.
Value
,
scope
*
scope
)
error
{
dt
,
st
:=
dv
.
Type
(),
sv
.
Type
()
if
fv
,
ok
:=
c
.
funcs
[
typePair
{
st
,
dt
}];
ok
{
// Apply default values.
if
fv
,
ok
:=
c
.
defaultingFuncs
[
st
];
ok
{
if
c
.
Debug
!=
nil
{
c
.
Debug
.
Logf
(
"Applying defaults for '%v'"
,
st
)
}
args
:=
[]
reflect
.
Value
{
sv
.
Addr
()}
fv
.
Call
(
args
)
}
// Convert sv to dv.
if
fv
,
ok
:=
c
.
conversionFuncs
[
typePair
{
st
,
dt
}];
ok
{
if
c
.
Debug
!=
nil
{
c
.
Debug
.
Logf
(
"Calling custom conversion of '%v' to '%v'"
,
st
,
dt
)
}
...
...
@@ -398,10 +445,10 @@ func (c *Converter) defaultConvert(sv, dv reflect.Value, scope *scope) error {
return
scope
.
error
(
"Cannot set dest. (Tried to deep copy something with unexported fields?)"
)
}
if
!
scope
.
flags
.
IsSet
(
AllowDifferentFieldTypeNames
)
&&
c
.
NameFunc
(
dt
)
!=
c
.
N
ameFunc
(
st
)
{
if
!
scope
.
flags
.
IsSet
(
AllowDifferentFieldTypeNames
)
&&
c
.
nameFunc
(
dt
)
!=
c
.
n
ameFunc
(
st
)
{
return
scope
.
error
(
"type names don't match (%v, %v), and no conversion 'func (%v, %v) error' registered."
,
c
.
NameFunc
(
st
),
c
.
N
ameFunc
(
dt
),
st
,
dt
)
c
.
nameFunc
(
st
),
c
.
n
ameFunc
(
dt
),
st
,
dt
)
}
switch
st
.
Kind
()
{
...
...
@@ -498,6 +545,7 @@ func toKVValue(v reflect.Value) kvValue {
case
reflect
.
Struct
:
return
structAdaptor
(
v
)
}
return
nil
}
...
...
pkg/conversion/converter_test.go
View file @
1ddb68d8
...
...
@@ -118,14 +118,14 @@ func TestConverter_CallsRegisteredFunctions(t *testing.T) {
type
C
struct
{}
c
:=
NewConverter
()
c
.
Debug
=
t
err
:=
c
.
Register
(
func
(
in
*
A
,
out
*
B
,
s
Scope
)
error
{
err
:=
c
.
Register
ConversionFunc
(
func
(
in
*
A
,
out
*
B
,
s
Scope
)
error
{
out
.
Bar
=
in
.
Foo
return
s
.
Convert
(
&
in
.
Baz
,
&
out
.
Baz
,
0
)
})
if
err
!=
nil
{
t
.
Fatalf
(
"unexpected error %v"
,
err
)
}
err
=
c
.
Register
(
func
(
in
*
B
,
out
*
A
,
s
Scope
)
error
{
err
=
c
.
Register
ConversionFunc
(
func
(
in
*
B
,
out
*
A
,
s
Scope
)
error
{
out
.
Foo
=
in
.
Bar
return
s
.
Convert
(
&
in
.
Baz
,
&
out
.
Baz
,
0
)
})
...
...
@@ -161,7 +161,7 @@ func TestConverter_CallsRegisteredFunctions(t *testing.T) {
t
.
Errorf
(
"expected %v, got %v"
,
e
,
a
)
}
err
=
c
.
Register
(
func
(
in
*
A
,
out
*
C
,
s
Scope
)
error
{
err
=
c
.
Register
ConversionFunc
(
func
(
in
*
A
,
out
*
C
,
s
Scope
)
error
{
return
fmt
.
Errorf
(
"C can't store an A, silly"
)
})
if
err
!=
nil
{
...
...
@@ -184,7 +184,7 @@ func TestConverter_fuzz(t *testing.T) {
f
:=
fuzz
.
New
()
.
NilChance
(
.5
)
.
NumElements
(
0
,
100
)
c
:=
NewConverter
()
c
.
N
ameFunc
=
func
(
t
reflect
.
Type
)
string
{
c
.
n
ameFunc
=
func
(
t
reflect
.
Type
)
string
{
// Hide the fact that we don't have separate packages for these things.
return
map
[
reflect
.
Type
]
string
{
reflect
.
TypeOf
(
TestType1
{})
:
"TestType1"
,
...
...
@@ -270,7 +270,7 @@ func TestConverter_tags(t *testing.T) {
}
c
:=
NewConverter
()
c
.
Debug
=
t
err
:=
c
.
Register
(
err
:=
c
.
Register
ConversionFunc
(
func
(
in
*
string
,
out
*
string
,
s
Scope
)
error
{
if
e
,
a
:=
"foo"
,
s
.
SrcTag
()
.
Get
(
"test"
);
e
!=
a
{
t
.
Errorf
(
"expected %v, got %v"
,
e
,
a
)
...
...
@@ -296,7 +296,7 @@ func TestConverter_meta(t *testing.T) {
c
:=
NewConverter
()
c
.
Debug
=
t
checks
:=
0
err
:=
c
.
Register
(
err
:=
c
.
Register
ConversionFunc
(
func
(
in
*
Foo
,
out
*
Bar
,
s
Scope
)
error
{
if
s
.
Meta
()
==
nil
||
s
.
Meta
()
.
SrcVersion
!=
"test"
||
s
.
Meta
()
.
DestVersion
!=
"passes"
{
t
.
Errorf
(
"Meta did not get passed!"
)
...
...
@@ -309,7 +309,7 @@ func TestConverter_meta(t *testing.T) {
if
err
!=
nil
{
t
.
Fatalf
(
"Unexpected error: %v"
,
err
)
}
err
=
c
.
Register
(
err
=
c
.
Register
ConversionFunc
(
func
(
in
*
string
,
out
*
string
,
s
Scope
)
error
{
if
s
.
Meta
()
==
nil
||
s
.
Meta
()
.
SrcVersion
!=
"test"
||
s
.
Meta
()
.
DestVersion
!=
"passes"
{
t
.
Errorf
(
"Meta did not get passed a second time!"
)
...
...
pkg/conversion/scheme.go
View file @
1ddb68d8
...
...
@@ -63,7 +63,7 @@ func NewScheme() *Scheme {
InternalVersion
:
""
,
MetaFactory
:
DefaultMetaFactory
,
}
s
.
converter
.
N
ameFunc
=
s
.
nameFunc
s
.
converter
.
n
ameFunc
=
s
.
nameFunc
return
s
}
...
...
@@ -194,7 +194,7 @@ func (s *Scheme) NewObject(versionName, kind string) (interface{}, error) {
// add conversion functions for things with changed/removed fields.
func
(
s
*
Scheme
)
AddConversionFuncs
(
conversionFuncs
...
interface
{})
error
{
for
_
,
f
:=
range
conversionFuncs
{
if
err
:=
s
.
converter
.
Register
(
f
);
err
!=
nil
{
if
err
:=
s
.
converter
.
Register
ConversionFunc
(
f
);
err
!=
nil
{
return
err
}
}
...
...
@@ -209,6 +209,29 @@ func (s *Scheme) AddStructFieldConversion(srcFieldType interface{}, srcFieldName
return
s
.
converter
.
SetStructFieldCopy
(
srcFieldType
,
srcFieldName
,
destFieldType
,
destFieldName
)
}
// AddDefaultingFuncs adds functions to the list of default-value functions.
// Each of the given functions is responsible for applying default values
// when converting an instance of a versioned API object into an internal
// API object. These functions do not need to handle sub-objects. We deduce
// how to call these functions from the types of their two parameters.
//
// s.AddDefaultingFuncs(
// func(obj *v1beta1.Pod) {
// if obj.OptionalField == "" {
// obj.OptionalField = "DefaultValue"
// }
// },
// )
func
(
s
*
Scheme
)
AddDefaultingFuncs
(
defaultingFuncs
...
interface
{})
error
{
for
_
,
f
:=
range
defaultingFuncs
{
err
:=
s
.
converter
.
RegisterDefaultingFunc
(
f
)
if
err
!=
nil
{
return
err
}
}
return
nil
}
// Convert will attempt to convert in into out. Both must be pointers. For easy
// testing of conversion functions. Returns an error if the conversion isn't
// possible. You can call this with types that haven't been registered (for example,
...
...
pkg/runtime/scheme.go
View file @
1ddb68d8
...
...
@@ -265,7 +265,8 @@ func (s *Scheme) Log(l conversion.DebugLogger) {
// AddConversionFuncs adds a function to the list of conversion functions. The given
// function should know how to convert between two API objects. We deduce how to call
// it from the types of its two parameters; see the comment for Converter.Register.
// it from the types of its two parameters; see the comment for
// Converter.RegisterConversionFunction.
//
// Note that, if you need to copy sub-objects that didn't change, it's safe to call
// Convert() inside your conversionFuncs, as long as you don't start a conversion
...
...
@@ -287,6 +288,13 @@ func (s *Scheme) AddStructFieldConversion(srcFieldType interface{}, srcFieldName
return
s
.
raw
.
AddStructFieldConversion
(
srcFieldType
,
srcFieldName
,
destFieldType
,
destFieldName
)
}
// AddDefaultingFuncs adds a function to the list of value-defaulting functions.
// We deduce how to call it from the types of its two parameters; see the
// comment for Converter.RegisterDefaultingFunction.
func
(
s
*
Scheme
)
AddDefaultingFuncs
(
defaultingFuncs
...
interface
{})
error
{
return
s
.
raw
.
AddDefaultingFuncs
(
defaultingFuncs
...
)
}
// Convert will attempt to convert in into out. Both must be pointers.
// For easy testing of conversion functions. Returns an error if the conversion isn't
// possible.
...
...
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