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
340802b0
Commit
340802b0
authored
Jul 06, 2018
by
David Eads
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
name runtime.Schemes so we can see which one fails
parent
d3731fe0
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
248 additions
and
117 deletions
+248
-117
BUILD
staging/src/BUILD
+1
-0
customresource_handler.go
...ensions-apiserver/pkg/apiserver/customresource_handler.go
+12
-2
BUILD
staging/src/k8s.io/apimachinery/pkg/runtime/BUILD
+1
-0
error.go
staging/src/k8s.io/apimachinery/pkg/runtime/error.go
+18
-17
scheme.go
staging/src/k8s.io/apimachinery/pkg/runtime/scheme.go
+18
-5
json_test.go
....io/apimachinery/pkg/runtime/serializer/json/json_test.go
+3
-3
versioning.go
...machinery/pkg/runtime/serializer/versioning/versioning.go
+8
-14
versioning_test.go
...nery/pkg/runtime/serializer/versioning/versioning_test.go
+3
-2
BUILD
staging/src/k8s.io/apimachinery/pkg/util/naming/BUILD
+29
-0
from_stack.go
...ing/src/k8s.io/apimachinery/pkg/util/naming/from_stack.go
+93
-0
from_stack_test.go
...rc/k8s.io/apimachinery/pkg/util/naming/from_stack_test.go
+56
-0
BUILD
staging/src/k8s.io/client-go/tools/cache/BUILD
+1
-0
reflector.go
staging/src/k8s.io/client-go/tools/cache/reflector.go
+3
-72
serializer.go
test/integration/framework/serializer.go
+2
-2
No files found.
staging/src/BUILD
View file @
340802b0
...
@@ -47,6 +47,7 @@ filegroup(
...
@@ -47,6 +47,7 @@ filegroup(
"//staging/src/k8s.io/apimachinery/pkg/util/json:all-srcs",
"//staging/src/k8s.io/apimachinery/pkg/util/json:all-srcs",
"//staging/src/k8s.io/apimachinery/pkg/util/jsonmergepatch:all-srcs",
"//staging/src/k8s.io/apimachinery/pkg/util/jsonmergepatch:all-srcs",
"//staging/src/k8s.io/apimachinery/pkg/util/mergepatch:all-srcs",
"//staging/src/k8s.io/apimachinery/pkg/util/mergepatch:all-srcs",
"//staging/src/k8s.io/apimachinery/pkg/util/naming:all-srcs",
"//staging/src/k8s.io/apimachinery/pkg/util/net:all-srcs",
"//staging/src/k8s.io/apimachinery/pkg/util/net:all-srcs",
"//staging/src/k8s.io/apimachinery/pkg/util/proxy:all-srcs",
"//staging/src/k8s.io/apimachinery/pkg/util/proxy:all-srcs",
"//staging/src/k8s.io/apimachinery/pkg/util/rand:all-srcs",
"//staging/src/k8s.io/apimachinery/pkg/util/rand:all-srcs",
...
...
staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go
View file @
340802b0
...
@@ -606,7 +606,7 @@ func (s unstructuredNegotiatedSerializer) SupportedMediaTypes() []runtime.Serial
...
@@ -606,7 +606,7 @@ func (s unstructuredNegotiatedSerializer) SupportedMediaTypes() []runtime.Serial
}
}
func
(
s
unstructuredNegotiatedSerializer
)
EncoderForVersion
(
encoder
runtime
.
Encoder
,
gv
runtime
.
GroupVersioner
)
runtime
.
Encoder
{
func
(
s
unstructuredNegotiatedSerializer
)
EncoderForVersion
(
encoder
runtime
.
Encoder
,
gv
runtime
.
GroupVersioner
)
runtime
.
Encoder
{
return
versioning
.
NewCodec
(
encoder
,
nil
,
s
.
converter
,
Scheme
,
Scheme
,
Scheme
,
gv
,
nil
)
return
versioning
.
NewCodec
(
encoder
,
nil
,
s
.
converter
,
Scheme
,
Scheme
,
Scheme
,
gv
,
nil
,
"crdNegotiatedSerializer"
)
}
}
func
(
s
unstructuredNegotiatedSerializer
)
DecoderToVersion
(
decoder
runtime
.
Decoder
,
gv
runtime
.
GroupVersioner
)
runtime
.
Decoder
{
func
(
s
unstructuredNegotiatedSerializer
)
DecoderToVersion
(
decoder
runtime
.
Decoder
,
gv
runtime
.
GroupVersioner
)
runtime
.
Decoder
{
...
@@ -710,7 +710,17 @@ func (t crdConversionRESTOptionsGetter) GetRESTOptions(resource schema.GroupReso
...
@@ -710,7 +710,17 @@ func (t crdConversionRESTOptionsGetter) GetRESTOptions(resource schema.GroupReso
dropInvalidMetadata
:
true
,
dropInvalidMetadata
:
true
,
}}
}}
c
:=
schemaCoercingConverter
{
delegate
:
t
.
converter
,
validator
:
unstructuredSchemaCoercer
{}}
c
:=
schemaCoercingConverter
{
delegate
:
t
.
converter
,
validator
:
unstructuredSchemaCoercer
{}}
ret
.
StorageConfig
.
Codec
=
versioning
.
NewCodec
(
ret
.
StorageConfig
.
Codec
,
d
,
c
,
&
unstructuredCreator
{},
crdserverscheme
.
NewUnstructuredObjectTyper
(),
&
unstructuredDefaulter
{
delegate
:
Scheme
},
t
.
encoderVersion
,
t
.
decoderVersion
)
ret
.
StorageConfig
.
Codec
=
versioning
.
NewCodec
(
ret
.
StorageConfig
.
Codec
,
d
,
c
,
&
unstructuredCreator
{},
crdserverscheme
.
NewUnstructuredObjectTyper
(),
&
unstructuredDefaulter
{
delegate
:
Scheme
},
t
.
encoderVersion
,
t
.
decoderVersion
,
"crdRESTOptions"
,
)
}
}
return
ret
,
err
return
ret
,
err
}
}
...
...
staging/src/k8s.io/apimachinery/pkg/runtime/BUILD
View file @
340802b0
...
@@ -63,6 +63,7 @@ go_library(
...
@@ -63,6 +63,7 @@ go_library(
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/json:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/json:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/naming:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
...
...
staging/src/k8s.io/apimachinery/pkg/runtime/error.go
View file @
340802b0
...
@@ -24,46 +24,47 @@ import (
...
@@ -24,46 +24,47 @@ import (
)
)
type
notRegisteredErr
struct
{
type
notRegisteredErr
struct
{
gvk
schema
.
GroupVersionKind
schemeName
string
target
GroupVersioner
gvk
schema
.
GroupVersionKind
t
reflect
.
Type
target
GroupVersioner
t
reflect
.
Type
}
}
func
NewNotRegisteredErrForKind
(
gvk
schema
.
GroupVersionKind
)
error
{
func
NewNotRegisteredErrForKind
(
schemeName
string
,
gvk
schema
.
GroupVersionKind
)
error
{
return
&
notRegisteredErr
{
gvk
:
gvk
}
return
&
notRegisteredErr
{
schemeName
:
schemeName
,
gvk
:
gvk
}
}
}
func
NewNotRegisteredErrForType
(
t
reflect
.
Type
)
error
{
func
NewNotRegisteredErrForType
(
schemeName
string
,
t
reflect
.
Type
)
error
{
return
&
notRegisteredErr
{
t
:
t
}
return
&
notRegisteredErr
{
schemeName
:
schemeName
,
t
:
t
}
}
}
func
NewNotRegisteredErrForTarget
(
t
reflect
.
Type
,
target
GroupVersioner
)
error
{
func
NewNotRegisteredErrForTarget
(
schemeName
string
,
t
reflect
.
Type
,
target
GroupVersioner
)
error
{
return
&
notRegisteredErr
{
t
:
t
,
target
:
target
}
return
&
notRegisteredErr
{
schemeName
:
schemeName
,
t
:
t
,
target
:
target
}
}
}
func
NewNotRegisteredGVKErrForTarget
(
gvk
schema
.
GroupVersionKind
,
target
GroupVersioner
)
error
{
func
NewNotRegisteredGVKErrForTarget
(
schemeName
string
,
gvk
schema
.
GroupVersionKind
,
target
GroupVersioner
)
error
{
return
&
notRegisteredErr
{
gvk
:
gvk
,
target
:
target
}
return
&
notRegisteredErr
{
schemeName
:
schemeName
,
gvk
:
gvk
,
target
:
target
}
}
}
func
(
k
*
notRegisteredErr
)
Error
()
string
{
func
(
k
*
notRegisteredErr
)
Error
()
string
{
if
k
.
t
!=
nil
&&
k
.
target
!=
nil
{
if
k
.
t
!=
nil
&&
k
.
target
!=
nil
{
return
fmt
.
Sprintf
(
"%v is not suitable for converting to %q
"
,
k
.
t
,
k
.
target
)
return
fmt
.
Sprintf
(
"%v is not suitable for converting to %q
in scheme %q"
,
k
.
t
,
k
.
target
,
k
.
schemeName
)
}
}
nullGVK
:=
schema
.
GroupVersionKind
{}
nullGVK
:=
schema
.
GroupVersionKind
{}
if
k
.
gvk
!=
nullGVK
&&
k
.
target
!=
nil
{
if
k
.
gvk
!=
nullGVK
&&
k
.
target
!=
nil
{
return
fmt
.
Sprintf
(
"%q is not suitable for converting to %q
"
,
k
.
gvk
.
GroupVersion
(),
k
.
target
)
return
fmt
.
Sprintf
(
"%q is not suitable for converting to %q
in scheme %q"
,
k
.
gvk
.
GroupVersion
(),
k
.
target
,
k
.
schemeName
)
}
}
if
k
.
t
!=
nil
{
if
k
.
t
!=
nil
{
return
fmt
.
Sprintf
(
"no kind is registered for the type %v
"
,
k
.
t
)
return
fmt
.
Sprintf
(
"no kind is registered for the type %v
in scheme %q"
,
k
.
t
,
k
.
schemeName
)
}
}
if
len
(
k
.
gvk
.
Kind
)
==
0
{
if
len
(
k
.
gvk
.
Kind
)
==
0
{
return
fmt
.
Sprintf
(
"no version %q has been registered
"
,
k
.
gvk
.
GroupVersion
()
)
return
fmt
.
Sprintf
(
"no version %q has been registered
in scheme %q"
,
k
.
gvk
.
GroupVersion
(),
k
.
schemeName
)
}
}
if
k
.
gvk
.
Version
==
APIVersionInternal
{
if
k
.
gvk
.
Version
==
APIVersionInternal
{
return
fmt
.
Sprintf
(
"no kind %q is registered for the internal version of group %q
"
,
k
.
gvk
.
Kind
,
k
.
gvk
.
Group
)
return
fmt
.
Sprintf
(
"no kind %q is registered for the internal version of group %q
in scheme %q"
,
k
.
gvk
.
Kind
,
k
.
gvk
.
Group
,
k
.
schemeName
)
}
}
return
fmt
.
Sprintf
(
"no kind %q is registered for version %q
"
,
k
.
gvk
.
Kind
,
k
.
gvk
.
GroupVersion
()
)
return
fmt
.
Sprintf
(
"no kind %q is registered for version %q
in scheme %q"
,
k
.
gvk
.
Kind
,
k
.
gvk
.
GroupVersion
(),
k
.
schemeName
)
}
}
// IsNotRegisteredError returns true if the error indicates the provided
// IsNotRegisteredError returns true if the error indicates the provided
...
...
staging/src/k8s.io/apimachinery/pkg/runtime/scheme.go
View file @
340802b0
...
@@ -20,11 +20,11 @@ import (
...
@@ -20,11 +20,11 @@ import (
"fmt"
"fmt"
"net/url"
"net/url"
"reflect"
"reflect"
"strings"
"strings"
"k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/naming"
utilruntime
"k8s.io/apimachinery/pkg/util/runtime"
utilruntime
"k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/sets"
)
)
...
@@ -79,6 +79,10 @@ type Scheme struct {
...
@@ -79,6 +79,10 @@ type Scheme struct {
// observedVersions keeps track of the order we've seen versions during type registration
// observedVersions keeps track of the order we've seen versions during type registration
observedVersions
[]
schema
.
GroupVersion
observedVersions
[]
schema
.
GroupVersion
// schemeName is the name of this scheme. If you don't specify a name, the stack of the NewScheme caller will be used.
// This is useful for error reporting to indicate the origin of the scheme.
schemeName
string
}
}
// FieldLabelConversionFunc converts a field selector to internal representation.
// FieldLabelConversionFunc converts a field selector to internal representation.
...
@@ -94,6 +98,7 @@ func NewScheme() *Scheme {
...
@@ -94,6 +98,7 @@ func NewScheme() *Scheme {
fieldLabelConversionFuncs
:
map
[
string
]
map
[
string
]
FieldLabelConversionFunc
{},
fieldLabelConversionFuncs
:
map
[
string
]
map
[
string
]
FieldLabelConversionFunc
{},
defaulterFuncs
:
map
[
reflect
.
Type
]
func
(
interface
{}){},
defaulterFuncs
:
map
[
reflect
.
Type
]
func
(
interface
{}){},
versionPriority
:
map
[
string
][]
string
{},
versionPriority
:
map
[
string
][]
string
{},
schemeName
:
naming
.
GetNameFromCallsite
(
internalPackages
...
),
}
}
s
.
converter
=
conversion
.
NewConverter
(
s
.
nameFunc
)
s
.
converter
=
conversion
.
NewConverter
(
s
.
nameFunc
)
...
@@ -250,7 +255,7 @@ func (s *Scheme) ObjectKinds(obj Object) ([]schema.GroupVersionKind, bool, error
...
@@ -250,7 +255,7 @@ func (s *Scheme) ObjectKinds(obj Object) ([]schema.GroupVersionKind, bool, error
gvks
,
ok
:=
s
.
typeToGVK
[
t
]
gvks
,
ok
:=
s
.
typeToGVK
[
t
]
if
!
ok
{
if
!
ok
{
return
nil
,
false
,
NewNotRegisteredErrForType
(
t
)
return
nil
,
false
,
NewNotRegisteredErrForType
(
s
.
schemeName
,
t
)
}
}
_
,
unversionedType
:=
s
.
unversionedTypes
[
t
]
_
,
unversionedType
:=
s
.
unversionedTypes
[
t
]
...
@@ -288,7 +293,7 @@ func (s *Scheme) New(kind schema.GroupVersionKind) (Object, error) {
...
@@ -288,7 +293,7 @@ func (s *Scheme) New(kind schema.GroupVersionKind) (Object, error) {
if
t
,
exists
:=
s
.
unversionedKinds
[
kind
.
Kind
];
exists
{
if
t
,
exists
:=
s
.
unversionedKinds
[
kind
.
Kind
];
exists
{
return
reflect
.
New
(
t
)
.
Interface
()
.
(
Object
),
nil
return
reflect
.
New
(
t
)
.
Interface
()
.
(
Object
),
nil
}
}
return
nil
,
NewNotRegisteredErrForKind
(
kind
)
return
nil
,
NewNotRegisteredErrForKind
(
s
.
schemeName
,
kind
)
}
}
// AddGenericConversionFunc adds a function that accepts the ConversionFunc call pattern
// AddGenericConversionFunc adds a function that accepts the ConversionFunc call pattern
...
@@ -536,7 +541,7 @@ func (s *Scheme) convertToVersion(copy bool, in Object, target GroupVersioner) (
...
@@ -536,7 +541,7 @@ func (s *Scheme) convertToVersion(copy bool, in Object, target GroupVersioner) (
kinds
,
ok
:=
s
.
typeToGVK
[
t
]
kinds
,
ok
:=
s
.
typeToGVK
[
t
]
if
!
ok
||
len
(
kinds
)
==
0
{
if
!
ok
||
len
(
kinds
)
==
0
{
return
nil
,
NewNotRegisteredErrForType
(
t
)
return
nil
,
NewNotRegisteredErrForType
(
s
.
schemeName
,
t
)
}
}
gvk
,
ok
:=
target
.
KindForGroupVersionKinds
(
kinds
)
gvk
,
ok
:=
target
.
KindForGroupVersionKinds
(
kinds
)
...
@@ -549,7 +554,7 @@ func (s *Scheme) convertToVersion(copy bool, in Object, target GroupVersioner) (
...
@@ -549,7 +554,7 @@ func (s *Scheme) convertToVersion(copy bool, in Object, target GroupVersioner) (
}
}
return
copyAndSetTargetKind
(
copy
,
in
,
unversionedKind
)
return
copyAndSetTargetKind
(
copy
,
in
,
unversionedKind
)
}
}
return
nil
,
NewNotRegisteredErrForTarget
(
t
,
target
)
return
nil
,
NewNotRegisteredErrForTarget
(
s
.
schemeName
,
t
,
target
)
}
}
// target wants to use the existing type, set kind and return (no conversion necessary)
// target wants to use the existing type, set kind and return (no conversion necessary)
...
@@ -759,3 +764,11 @@ func (s *Scheme) addObservedVersion(version schema.GroupVersion) {
...
@@ -759,3 +764,11 @@ func (s *Scheme) addObservedVersion(version schema.GroupVersion) {
s
.
observedVersions
=
append
(
s
.
observedVersions
,
version
)
s
.
observedVersions
=
append
(
s
.
observedVersions
,
version
)
}
}
func
(
s
*
Scheme
)
Name
()
string
{
return
s
.
schemeName
}
// internalPackages are packages that ignored when creating a default reflector name. These packages are in the common
// call chains to NewReflector, so they'd be low entropy names for reflectors
var
internalPackages
=
[]
string
{
"k8s.io/apimachinery/pkg/runtime/scheme.go"
}
staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json/json_test.go
View file @
340802b0
...
@@ -180,7 +180,7 @@ func TestDecode(t *testing.T) {
...
@@ -180,7 +180,7 @@ func TestDecode(t *testing.T) {
{
{
data
:
[]
byte
(
`{"kind":"Test","apiVersion":"other/blah","value":1,"Other":"test"}`
),
data
:
[]
byte
(
`{"kind":"Test","apiVersion":"other/blah","value":1,"Other":"test"}`
),
into
:
&
testDecodable
{},
into
:
&
testDecodable
{},
typer
:
&
mockTyper
{
err
:
runtime
.
NewNotRegisteredErrForKind
(
schema
.
GroupVersionKind
{
Kind
:
"Test"
,
Group
:
"other"
,
Version
:
"blah"
})},
typer
:
&
mockTyper
{
err
:
runtime
.
NewNotRegisteredErrForKind
(
"mock"
,
schema
.
GroupVersionKind
{
Kind
:
"Test"
,
Group
:
"other"
,
Version
:
"blah"
})},
expectedGVK
:
&
schema
.
GroupVersionKind
{
Kind
:
"Test"
,
Group
:
"other"
,
Version
:
"blah"
},
expectedGVK
:
&
schema
.
GroupVersionKind
{
Kind
:
"Test"
,
Group
:
"other"
,
Version
:
"blah"
},
expectedObject
:
&
testDecodable
{
expectedObject
:
&
testDecodable
{
Other
:
"test"
,
Other
:
"test"
,
...
@@ -257,7 +257,7 @@ func TestDecode(t *testing.T) {
...
@@ -257,7 +257,7 @@ func TestDecode(t *testing.T) {
// "VaLue" should have been "value"
// "VaLue" should have been "value"
data
:
[]
byte
(
`{"kind":"Test","apiVersion":"other/blah","VaLue":1,"Other":"test"}`
),
data
:
[]
byte
(
`{"kind":"Test","apiVersion":"other/blah","VaLue":1,"Other":"test"}`
),
into
:
&
testDecodable
{},
into
:
&
testDecodable
{},
typer
:
&
mockTyper
{
err
:
runtime
.
NewNotRegisteredErrForKind
(
schema
.
GroupVersionKind
{
Kind
:
"Test"
,
Group
:
"other"
,
Version
:
"blah"
})},
typer
:
&
mockTyper
{
err
:
runtime
.
NewNotRegisteredErrForKind
(
"mock"
,
schema
.
GroupVersionKind
{
Kind
:
"Test"
,
Group
:
"other"
,
Version
:
"blah"
})},
expectedGVK
:
&
schema
.
GroupVersionKind
{
Kind
:
"Test"
,
Group
:
"other"
,
Version
:
"blah"
},
expectedGVK
:
&
schema
.
GroupVersionKind
{
Kind
:
"Test"
,
Group
:
"other"
,
Version
:
"blah"
},
expectedObject
:
&
testDecodable
{
expectedObject
:
&
testDecodable
{
Other
:
"test"
,
Other
:
"test"
,
...
@@ -268,7 +268,7 @@ func TestDecode(t *testing.T) {
...
@@ -268,7 +268,7 @@ func TestDecode(t *testing.T) {
// "b" should have been "B", "I" should have been "i"
// "b" should have been "B", "I" should have been "i"
data
:
[]
byte
(
`{"kind":"Test","apiVersion":"other/blah","spec": {"A": 1, "b": 2, "h": 3, "I": 4}}`
),
data
:
[]
byte
(
`{"kind":"Test","apiVersion":"other/blah","spec": {"A": 1, "b": 2, "h": 3, "I": 4}}`
),
into
:
&
testDecodable
{},
into
:
&
testDecodable
{},
typer
:
&
mockTyper
{
err
:
runtime
.
NewNotRegisteredErrForKind
(
schema
.
GroupVersionKind
{
Kind
:
"Test"
,
Group
:
"other"
,
Version
:
"blah"
})},
typer
:
&
mockTyper
{
err
:
runtime
.
NewNotRegisteredErrForKind
(
"mock"
,
schema
.
GroupVersionKind
{
Kind
:
"Test"
,
Group
:
"other"
,
Version
:
"blah"
})},
expectedGVK
:
&
schema
.
GroupVersionKind
{
Kind
:
"Test"
,
Group
:
"other"
,
Version
:
"blah"
},
expectedGVK
:
&
schema
.
GroupVersionKind
{
Kind
:
"Test"
,
Group
:
"other"
,
Version
:
"blah"
},
expectedObject
:
&
testDecodable
{
expectedObject
:
&
testDecodable
{
Spec
:
DecodableSpec
{
A
:
1
,
H
:
3
},
Spec
:
DecodableSpec
{
A
:
1
,
H
:
3
},
...
...
staging/src/k8s.io/apimachinery/pkg/runtime/serializer/versioning/versioning.go
View file @
340802b0
...
@@ -24,18 +24,6 @@ import (
...
@@ -24,18 +24,6 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/schema"
)
)
// NewCodecForScheme is a convenience method for callers that are using a scheme.
func
NewCodecForScheme
(
// TODO: I should be a scheme interface?
scheme
*
runtime
.
Scheme
,
encoder
runtime
.
Encoder
,
decoder
runtime
.
Decoder
,
encodeVersion
runtime
.
GroupVersioner
,
decodeVersion
runtime
.
GroupVersioner
,
)
runtime
.
Codec
{
return
NewCodec
(
encoder
,
decoder
,
runtime
.
UnsafeObjectConvertor
(
scheme
),
scheme
,
scheme
,
nil
,
encodeVersion
,
decodeVersion
)
}
// NewDefaultingCodecForScheme is a convenience method for callers that are using a scheme.
// NewDefaultingCodecForScheme is a convenience method for callers that are using a scheme.
func
NewDefaultingCodecForScheme
(
func
NewDefaultingCodecForScheme
(
// TODO: I should be a scheme interface?
// TODO: I should be a scheme interface?
...
@@ -45,7 +33,7 @@ func NewDefaultingCodecForScheme(
...
@@ -45,7 +33,7 @@ func NewDefaultingCodecForScheme(
encodeVersion
runtime
.
GroupVersioner
,
encodeVersion
runtime
.
GroupVersioner
,
decodeVersion
runtime
.
GroupVersioner
,
decodeVersion
runtime
.
GroupVersioner
,
)
runtime
.
Codec
{
)
runtime
.
Codec
{
return
NewCodec
(
encoder
,
decoder
,
runtime
.
UnsafeObjectConvertor
(
scheme
),
scheme
,
scheme
,
scheme
,
encodeVersion
,
decodeVersion
)
return
NewCodec
(
encoder
,
decoder
,
runtime
.
UnsafeObjectConvertor
(
scheme
),
scheme
,
scheme
,
scheme
,
encodeVersion
,
decodeVersion
,
scheme
.
Name
()
)
}
}
// NewCodec takes objects in their internal versions and converts them to external versions before
// NewCodec takes objects in their internal versions and converts them to external versions before
...
@@ -60,6 +48,7 @@ func NewCodec(
...
@@ -60,6 +48,7 @@ func NewCodec(
defaulter
runtime
.
ObjectDefaulter
,
defaulter
runtime
.
ObjectDefaulter
,
encodeVersion
runtime
.
GroupVersioner
,
encodeVersion
runtime
.
GroupVersioner
,
decodeVersion
runtime
.
GroupVersioner
,
decodeVersion
runtime
.
GroupVersioner
,
originalSchemeName
string
,
)
runtime
.
Codec
{
)
runtime
.
Codec
{
internal
:=
&
codec
{
internal
:=
&
codec
{
encoder
:
encoder
,
encoder
:
encoder
,
...
@@ -71,6 +60,8 @@ func NewCodec(
...
@@ -71,6 +60,8 @@ func NewCodec(
encodeVersion
:
encodeVersion
,
encodeVersion
:
encodeVersion
,
decodeVersion
:
decodeVersion
,
decodeVersion
:
decodeVersion
,
originalSchemeName
:
originalSchemeName
,
}
}
return
internal
return
internal
}
}
...
@@ -85,6 +76,9 @@ type codec struct {
...
@@ -85,6 +76,9 @@ type codec struct {
encodeVersion
runtime
.
GroupVersioner
encodeVersion
runtime
.
GroupVersioner
decodeVersion
runtime
.
GroupVersioner
decodeVersion
runtime
.
GroupVersioner
// originalSchemeName is optional, but when filled in it holds the name of the scheme from which this codec originates
originalSchemeName
string
}
}
// Decode attempts a decode of the object, then tries to convert it to the internal version. If into is provided and the decoding is
// Decode attempts a decode of the object, then tries to convert it to the internal version. If into is provided and the decoding is
...
@@ -182,7 +176,7 @@ func (c *codec) Encode(obj runtime.Object, w io.Writer) error {
...
@@ -182,7 +176,7 @@ func (c *codec) Encode(obj runtime.Object, w io.Writer) error {
}
}
targetGVK
,
ok
:=
c
.
encodeVersion
.
KindForGroupVersionKinds
([]
schema
.
GroupVersionKind
{
objGVK
})
targetGVK
,
ok
:=
c
.
encodeVersion
.
KindForGroupVersionKinds
([]
schema
.
GroupVersionKind
{
objGVK
})
if
!
ok
{
if
!
ok
{
return
runtime
.
NewNotRegisteredGVKErrForTarget
(
objGVK
,
c
.
encodeVersion
)
return
runtime
.
NewNotRegisteredGVKErrForTarget
(
c
.
originalSchemeName
,
objGVK
,
c
.
encodeVersion
)
}
}
if
targetGVK
==
objGVK
{
if
targetGVK
==
objGVK
{
return
c
.
encoder
.
Encode
(
obj
,
w
)
return
c
.
encoder
.
Encode
(
obj
,
w
)
...
...
staging/src/k8s.io/apimachinery/pkg/runtime/serializer/versioning/versioning_test.go
View file @
340802b0
...
@@ -72,7 +72,7 @@ func (d *testNestedDecodable) DecodeNestedObjects(_ runtime.Decoder) error {
...
@@ -72,7 +72,7 @@ func (d *testNestedDecodable) DecodeNestedObjects(_ runtime.Decoder) error {
func
TestNestedDecode
(
t
*
testing
.
T
)
{
func
TestNestedDecode
(
t
*
testing
.
T
)
{
n
:=
&
testNestedDecodable
{
nestedErr
:
fmt
.
Errorf
(
"unable to decode"
)}
n
:=
&
testNestedDecodable
{
nestedErr
:
fmt
.
Errorf
(
"unable to decode"
)}
decoder
:=
&
mockSerializer
{
obj
:
n
}
decoder
:=
&
mockSerializer
{
obj
:
n
}
codec
:=
NewCodec
(
nil
,
decoder
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
codec
:=
NewCodec
(
nil
,
decoder
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
"TestNestedDecode"
)
if
_
,
_
,
err
:=
codec
.
Decode
([]
byte
(
`{}`
),
nil
,
n
);
err
!=
n
.
nestedErr
{
if
_
,
_
,
err
:=
codec
.
Decode
([]
byte
(
`{}`
),
nil
,
n
);
err
!=
n
.
nestedErr
{
t
.
Errorf
(
"unexpected error: %v"
,
err
)
t
.
Errorf
(
"unexpected error: %v"
,
err
)
}
}
...
@@ -92,6 +92,7 @@ func TestNestedEncode(t *testing.T) {
...
@@ -92,6 +92,7 @@ func TestNestedEncode(t *testing.T) {
&
mockTyper
{
gvks
:
[]
schema
.
GroupVersionKind
{{
Kind
:
"test"
}}},
&
mockTyper
{
gvks
:
[]
schema
.
GroupVersionKind
{{
Kind
:
"test"
}}},
nil
,
nil
,
schema
.
GroupVersion
{
Group
:
"other"
},
nil
,
schema
.
GroupVersion
{
Group
:
"other"
},
nil
,
"TestNestedEncode"
,
)
)
if
err
:=
codec
.
Encode
(
n
,
ioutil
.
Discard
);
err
!=
n2
.
nestedErr
{
if
err
:=
codec
.
Encode
(
n
,
ioutil
.
Discard
);
err
!=
n2
.
nestedErr
{
t
.
Errorf
(
"unexpected error: %v"
,
err
)
t
.
Errorf
(
"unexpected error: %v"
,
err
)
...
@@ -231,7 +232,7 @@ func TestDecode(t *testing.T) {
...
@@ -231,7 +232,7 @@ func TestDecode(t *testing.T) {
for
i
,
test
:=
range
testCases
{
for
i
,
test
:=
range
testCases
{
t
.
Logf
(
"%d"
,
i
)
t
.
Logf
(
"%d"
,
i
)
s
:=
NewCodec
(
test
.
serializer
,
test
.
serializer
,
test
.
convertor
,
test
.
creater
,
test
.
typer
,
test
.
defaulter
,
test
.
encodes
,
test
.
decodes
)
s
:=
NewCodec
(
test
.
serializer
,
test
.
serializer
,
test
.
convertor
,
test
.
creater
,
test
.
typer
,
test
.
defaulter
,
test
.
encodes
,
test
.
decodes
,
fmt
.
Sprintf
(
"mock-%d"
,
i
)
)
obj
,
gvk
,
err
:=
s
.
Decode
([]
byte
(
`{}`
),
test
.
defaultGVK
,
test
.
into
)
obj
,
gvk
,
err
:=
s
.
Decode
([]
byte
(
`{}`
),
test
.
defaultGVK
,
test
.
into
)
if
!
reflect
.
DeepEqual
(
test
.
expectedGVK
,
gvk
)
{
if
!
reflect
.
DeepEqual
(
test
.
expectedGVK
,
gvk
)
{
...
...
staging/src/k8s.io/apimachinery/pkg/util/naming/BUILD
0 → 100644
View file @
340802b0
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = ["from_stack.go"],
importmap = "k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/util/naming",
importpath = "k8s.io/apimachinery/pkg/util/naming",
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = ["from_stack_test.go"],
embed = [":go_default_library"],
)
staging/src/k8s.io/apimachinery/pkg/util/naming/from_stack.go
0 → 100644
View file @
340802b0
/*
Copyright 2018 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.
*/
package
naming
import
(
"fmt"
"regexp"
goruntime
"runtime"
"runtime/debug"
"strconv"
"strings"
)
// GetNameFromCallsite walks back through the call stack until we find a caller from outside of the ignoredPackages
// it returns back a shortpath/filename:line to aid in identification of this reflector when it starts logging
func
GetNameFromCallsite
(
ignoredPackages
...
string
)
string
{
name
:=
"????"
const
maxStack
=
10
for
i
:=
1
;
i
<
maxStack
;
i
++
{
_
,
file
,
line
,
ok
:=
goruntime
.
Caller
(
i
)
if
!
ok
{
file
,
line
,
ok
=
extractStackCreator
()
if
!
ok
{
break
}
i
+=
maxStack
}
if
hasPackage
(
file
,
append
(
ignoredPackages
,
"/runtime/asm_"
))
{
continue
}
file
=
trimPackagePrefix
(
file
)
name
=
fmt
.
Sprintf
(
"%s:%d"
,
file
,
line
)
break
}
return
name
}
// hasPackage returns true if the file is in one of the ignored packages.
func
hasPackage
(
file
string
,
ignoredPackages
[]
string
)
bool
{
for
_
,
ignoredPackage
:=
range
ignoredPackages
{
if
strings
.
Contains
(
file
,
ignoredPackage
)
{
return
true
}
}
return
false
}
// trimPackagePrefix reduces duplicate values off the front of a package name.
func
trimPackagePrefix
(
file
string
)
string
{
if
l
:=
strings
.
LastIndex
(
file
,
"/vendor/"
);
l
>=
0
{
return
file
[
l
+
len
(
"/vendor/"
)
:
]
}
if
l
:=
strings
.
LastIndex
(
file
,
"/src/"
);
l
>=
0
{
return
file
[
l
+
5
:
]
}
if
l
:=
strings
.
LastIndex
(
file
,
"/pkg/"
);
l
>=
0
{
return
file
[
l
+
1
:
]
}
return
file
}
var
stackCreator
=
regexp
.
MustCompile
(
`(?m)^created by (.*)\n\s+(.*):(\d+) \+0x[[:xdigit:]]+$`
)
// extractStackCreator retrieves the goroutine file and line that launched this stack. Returns false
// if the creator cannot be located.
// TODO: Go does not expose this via runtime https://github.com/golang/go/issues/11440
func
extractStackCreator
()
(
string
,
int
,
bool
)
{
stack
:=
debug
.
Stack
()
matches
:=
stackCreator
.
FindStringSubmatch
(
string
(
stack
))
if
matches
==
nil
||
len
(
matches
)
!=
4
{
return
""
,
0
,
false
}
line
,
err
:=
strconv
.
Atoi
(
matches
[
3
])
if
err
!=
nil
{
return
""
,
0
,
false
}
return
matches
[
2
],
line
,
true
}
staging/src/k8s.io/apimachinery/pkg/util/naming/from_stack_test.go
0 → 100644
View file @
340802b0
/*
Copyright 2018 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.
*/
package
naming
import
"testing"
func
TestGetNameFromCallsite
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
name
string
ignoredPackages
[]
string
expected
string
}{
{
name
:
"simple"
,
expected
:
"k8s.io/apimachinery/pkg/util/naming/from_stack_test.go:50"
,
},
{
name
:
"ignore-package"
,
ignoredPackages
:
[]
string
{
"k8s.io/apimachinery/pkg/util/naming"
},
expected
:
"testing/testing.go:777"
,
},
{
name
:
"ignore-file"
,
ignoredPackages
:
[]
string
{
"k8s.io/apimachinery/pkg/util/naming/from_stack_test.go"
},
expected
:
"testing/testing.go:777"
,
},
{
name
:
"ignore-multiple"
,
ignoredPackages
:
[]
string
{
"k8s.io/apimachinery/pkg/util/naming/from_stack_test.go"
,
"testing/testing.go"
},
expected
:
"????"
,
},
}
for
_
,
tc
:=
range
tests
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
actual
:=
GetNameFromCallsite
(
tc
.
ignoredPackages
...
)
if
tc
.
expected
!=
actual
{
t
.
Fatalf
(
"expected %q, got %q"
,
tc
.
expected
,
actual
)
}
})
}
}
staging/src/k8s.io/client-go/tools/cache/BUILD
View file @
340802b0
...
@@ -74,6 +74,7 @@ go_library(
...
@@ -74,6 +74,7 @@ go_library(
"//staging/src/k8s.io/apimachinery/pkg/util/cache:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/cache:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/clock:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/clock:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/naming:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
...
...
staging/src/k8s.io/client-go/tools/cache/reflector.go
View file @
340802b0
...
@@ -24,9 +24,6 @@ import (
...
@@ -24,9 +24,6 @@ import (
"net"
"net"
"net/url"
"net/url"
"reflect"
"reflect"
"regexp"
goruntime
"runtime"
"runtime/debug"
"strconv"
"strconv"
"strings"
"strings"
"sync"
"sync"
...
@@ -40,6 +37,7 @@ import (
...
@@ -40,6 +37,7 @@ import (
metav1
"k8s.io/apimachinery/pkg/apis/meta/v1"
metav1
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/clock"
"k8s.io/apimachinery/pkg/util/clock"
"k8s.io/apimachinery/pkg/util/naming"
utilruntime
"k8s.io/apimachinery/pkg/util/runtime"
utilruntime
"k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/apimachinery/pkg/watch"
...
@@ -94,7 +92,7 @@ func NewNamespaceKeyedIndexerAndReflector(lw ListerWatcher, expectedType interfa
...
@@ -94,7 +92,7 @@ func NewNamespaceKeyedIndexerAndReflector(lw ListerWatcher, expectedType interfa
// resyncPeriod, so that you can use reflectors to periodically process everything as
// resyncPeriod, so that you can use reflectors to periodically process everything as
// well as incrementally processing the things that change.
// well as incrementally processing the things that change.
func
NewReflector
(
lw
ListerWatcher
,
expectedType
interface
{},
store
Store
,
resyncPeriod
time
.
Duration
)
*
Reflector
{
func
NewReflector
(
lw
ListerWatcher
,
expectedType
interface
{},
store
Store
,
resyncPeriod
time
.
Duration
)
*
Reflector
{
return
NewNamedReflector
(
getDefaultReflectorNam
e
(
internalPackages
...
),
lw
,
expectedType
,
store
,
resyncPeriod
)
return
NewNamedReflector
(
naming
.
GetNameFromCallsit
e
(
internalPackages
...
),
lw
,
expectedType
,
store
,
resyncPeriod
)
}
}
// reflectorDisambiguator is used to disambiguate started reflectors.
// reflectorDisambiguator is used to disambiguate started reflectors.
...
@@ -125,74 +123,7 @@ func makeValidPrometheusMetricLabel(in string) string {
...
@@ -125,74 +123,7 @@ func makeValidPrometheusMetricLabel(in string) string {
// internalPackages are packages that ignored when creating a default reflector name. These packages are in the common
// internalPackages are packages that ignored when creating a default reflector name. These packages are in the common
// call chains to NewReflector, so they'd be low entropy names for reflectors
// call chains to NewReflector, so they'd be low entropy names for reflectors
var
internalPackages
=
[]
string
{
"client-go/tools/cache/"
,
"/runtime/asm_"
}
var
internalPackages
=
[]
string
{
"client-go/tools/cache/"
}
// getDefaultReflectorName walks back through the call stack until we find a caller from outside of the ignoredPackages
// it returns back a shortpath/filename:line to aid in identification of this reflector when it starts logging
func
getDefaultReflectorName
(
ignoredPackages
...
string
)
string
{
name
:=
"????"
const
maxStack
=
10
for
i
:=
1
;
i
<
maxStack
;
i
++
{
_
,
file
,
line
,
ok
:=
goruntime
.
Caller
(
i
)
if
!
ok
{
file
,
line
,
ok
=
extractStackCreator
()
if
!
ok
{
break
}
i
+=
maxStack
}
if
hasPackage
(
file
,
ignoredPackages
)
{
continue
}
file
=
trimPackagePrefix
(
file
)
name
=
fmt
.
Sprintf
(
"%s:%d"
,
file
,
line
)
break
}
return
name
}
// hasPackage returns true if the file is in one of the ignored packages.
func
hasPackage
(
file
string
,
ignoredPackages
[]
string
)
bool
{
for
_
,
ignoredPackage
:=
range
ignoredPackages
{
if
strings
.
Contains
(
file
,
ignoredPackage
)
{
return
true
}
}
return
false
}
// trimPackagePrefix reduces duplicate values off the front of a package name.
func
trimPackagePrefix
(
file
string
)
string
{
if
l
:=
strings
.
LastIndex
(
file
,
"k8s.io/client-go/pkg/"
);
l
>=
0
{
return
file
[
l
+
len
(
"k8s.io/client-go/"
)
:
]
}
if
l
:=
strings
.
LastIndex
(
file
,
"/src/"
);
l
>=
0
{
return
file
[
l
+
5
:
]
}
if
l
:=
strings
.
LastIndex
(
file
,
"/pkg/"
);
l
>=
0
{
return
file
[
l
+
1
:
]
}
return
file
}
var
stackCreator
=
regexp
.
MustCompile
(
`(?m)^created by (.*)\n\s+(.*):(\d+) \+0x[[:xdigit:]]+$`
)
// extractStackCreator retrieves the goroutine file and line that launched this stack. Returns false
// if the creator cannot be located.
// TODO: Go does not expose this via runtime https://github.com/golang/go/issues/11440
func
extractStackCreator
()
(
string
,
int
,
bool
)
{
stack
:=
debug
.
Stack
()
matches
:=
stackCreator
.
FindStringSubmatch
(
string
(
stack
))
if
matches
==
nil
||
len
(
matches
)
!=
4
{
return
""
,
0
,
false
}
line
,
err
:=
strconv
.
Atoi
(
matches
[
3
])
if
err
!=
nil
{
return
""
,
0
,
false
}
return
matches
[
2
],
line
,
true
}
// Run starts a watch and handles watch events. Will restart the watch if it is closed.
// Run starts a watch and handles watch events. Will restart the watch if it is closed.
// Run will exit when stopCh is closed.
// Run will exit when stopCh is closed.
...
...
test/integration/framework/serializer.go
View file @
340802b0
...
@@ -45,9 +45,9 @@ func (s *wrappedSerializer) UniversalDeserializer() runtime.Decoder {
...
@@ -45,9 +45,9 @@ func (s *wrappedSerializer) UniversalDeserializer() runtime.Decoder {
}
}
func
(
s
*
wrappedSerializer
)
EncoderForVersion
(
encoder
runtime
.
Encoder
,
gv
runtime
.
GroupVersioner
)
runtime
.
Encoder
{
func
(
s
*
wrappedSerializer
)
EncoderForVersion
(
encoder
runtime
.
Encoder
,
gv
runtime
.
GroupVersioner
)
runtime
.
Encoder
{
return
versioning
.
NewCodec
(
encoder
,
nil
,
s
.
scheme
,
s
.
scheme
,
s
.
scheme
,
s
.
scheme
,
gv
,
nil
)
return
versioning
.
NewCodec
(
encoder
,
nil
,
s
.
scheme
,
s
.
scheme
,
s
.
scheme
,
s
.
scheme
,
gv
,
nil
,
s
.
scheme
.
Name
()
)
}
}
func
(
s
*
wrappedSerializer
)
DecoderToVersion
(
decoder
runtime
.
Decoder
,
gv
runtime
.
GroupVersioner
)
runtime
.
Decoder
{
func
(
s
*
wrappedSerializer
)
DecoderToVersion
(
decoder
runtime
.
Decoder
,
gv
runtime
.
GroupVersioner
)
runtime
.
Decoder
{
return
versioning
.
NewCodec
(
nil
,
decoder
,
s
.
scheme
,
s
.
scheme
,
s
.
scheme
,
s
.
scheme
,
nil
,
gv
)
return
versioning
.
NewCodec
(
nil
,
decoder
,
s
.
scheme
,
s
.
scheme
,
s
.
scheme
,
s
.
scheme
,
nil
,
gv
,
s
.
scheme
.
Name
()
)
}
}
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