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
97baad34
Unverified
Commit
97baad34
authored
Nov 10, 2018
by
k8s-ci-robot
Committed by
GitHub
Nov 10, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #67006 from mbohlool/crd_webhook_conversion
CRD webhook conversion
parents
344b42f0
d51d0164
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
35 changed files
with
809 additions
and
44 deletions
+809
-44
apiextensions.go
cmd/kube-apiserver/app/apiextensions.go
+5
-0
server.go
cmd/kube-apiserver/app/server.go
+2
-1
Godeps.json
...ing/src/k8s.io/apiextensions-apiserver/Godeps/Godeps.json
+12
-0
BUILD
...ng/src/k8s.io/apiextensions-apiserver/pkg/apiserver/BUILD
+1
-0
apiserver.go
...k8s.io/apiextensions-apiserver/pkg/apiserver/apiserver.go
+12
-1
BUILD
...io/apiextensions-apiserver/pkg/apiserver/conversion/BUILD
+8
-0
converter.go
...xtensions-apiserver/pkg/apiserver/conversion/converter.go
+47
-12
nop_converter.go
...sions-apiserver/pkg/apiserver/conversion/nop_converter.go
+3
-3
webhook_converter.go
...s-apiserver/pkg/apiserver/conversion/webhook_converter.go
+0
-0
customresource_handler.go
...ensions-apiserver/pkg/apiserver/customresource_handler.go
+16
-3
customresource_handler_test.go
...ns-apiserver/pkg/apiserver/customresource_handler_test.go
+12
-2
BUILD
...s.io/apiextensions-apiserver/pkg/cmd/server/options/BUILD
+3
-0
options.go
...apiextensions-apiserver/pkg/cmd/server/options/options.go
+14
-0
helpers.go
...8s.io/apiextensions-apiserver/test/integration/helpers.go
+2
-2
validation_test.go
...iextensions-apiserver/test/integration/validation_test.go
+1
-1
versioning_test.go
...iextensions-apiserver/test/integration/versioning_test.go
+1
-1
webhook.go
...apiserver/pkg/admission/plugin/webhook/generic/webhook.go
+1
-0
BUILD
test/e2e/apimachinery/BUILD
+3
-0
crd_conversion_webhook.go
test/e2e/apimachinery/crd_conversion_webhook.go
+0
-0
webhook.go
test/e2e/apimachinery/webhook.go
+14
-8
crd_util.go
test/e2e/framework/crd_util.go
+47
-10
BUILD
test/images/BUILD
+1
-0
BASEIMAGE
test/images/crd-conversion-webhook/BASEIMAGE
+4
-0
BUILD
test/images/crd-conversion-webhook/BUILD
+40
-0
Dockerfile
test/images/crd-conversion-webhook/Dockerfile
+18
-0
Makefile
test/images/crd-conversion-webhook/Makefile
+25
-0
README.md
test/images/crd-conversion-webhook/README.md
+11
-0
VERSION
test/images/crd-conversion-webhook/VERSION
+1
-0
config.go
test/images/crd-conversion-webhook/config.go
+51
-0
BUILD
test/images/crd-conversion-webhook/converter/BUILD
+47
-0
converter_test.go
...images/crd-conversion-webhook/converter/converter_test.go
+97
-0
example_converter.go
...ges/crd-conversion-webhook/converter/example_converter.go
+79
-0
framework.go
test/images/crd-conversion-webhook/converter/framework.go
+178
-0
main.go
test/images/crd-conversion-webhook/main.go
+52
-0
manifest.go
test/utils/image/manifest.go
+1
-0
No files found.
cmd/kube-apiserver/app/apiextensions.go
View file @
97baad34
...
@@ -28,6 +28,7 @@ import (
...
@@ -28,6 +28,7 @@ import (
genericapiserver
"k8s.io/apiserver/pkg/server"
genericapiserver
"k8s.io/apiserver/pkg/server"
genericoptions
"k8s.io/apiserver/pkg/server/options"
genericoptions
"k8s.io/apiserver/pkg/server/options"
utilfeature
"k8s.io/apiserver/pkg/util/feature"
utilfeature
"k8s.io/apiserver/pkg/util/feature"
"k8s.io/apiserver/pkg/util/webhook"
kubeexternalinformers
"k8s.io/client-go/informers"
kubeexternalinformers
"k8s.io/client-go/informers"
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
)
)
...
@@ -38,6 +39,8 @@ func createAPIExtensionsConfig(
...
@@ -38,6 +39,8 @@ func createAPIExtensionsConfig(
pluginInitializers
[]
admission
.
PluginInitializer
,
pluginInitializers
[]
admission
.
PluginInitializer
,
commandOptions
*
options
.
ServerRunOptions
,
commandOptions
*
options
.
ServerRunOptions
,
masterCount
int
,
masterCount
int
,
serviceResolver
webhook
.
ServiceResolver
,
authResolverWrapper
webhook
.
AuthenticationInfoResolverWrapper
,
)
(
*
apiextensionsapiserver
.
Config
,
error
)
{
)
(
*
apiextensionsapiserver
.
Config
,
error
)
{
// make a shallow copy to let us twiddle a few things
// make a shallow copy to let us twiddle a few things
// most of the config actually remains the same. We only need to mess with a couple items related to the particulars of the apiextensions
// most of the config actually remains the same. We only need to mess with a couple items related to the particulars of the apiextensions
...
@@ -74,6 +77,8 @@ func createAPIExtensionsConfig(
...
@@ -74,6 +77,8 @@ func createAPIExtensionsConfig(
ExtraConfig
:
apiextensionsapiserver
.
ExtraConfig
{
ExtraConfig
:
apiextensionsapiserver
.
ExtraConfig
{
CRDRESTOptionsGetter
:
apiextensionsoptions
.
NewCRDRESTOptionsGetter
(
etcdOptions
),
CRDRESTOptionsGetter
:
apiextensionsoptions
.
NewCRDRESTOptionsGetter
(
etcdOptions
),
MasterCount
:
masterCount
,
MasterCount
:
masterCount
,
AuthResolverWrapper
:
authResolverWrapper
,
ServiceResolver
:
serviceResolver
,
},
},
}
}
...
...
cmd/kube-apiserver/app/server.go
View file @
97baad34
...
@@ -165,7 +165,8 @@ func CreateServerChain(completedOptions completedServerRunOptions, stopCh <-chan
...
@@ -165,7 +165,8 @@ func CreateServerChain(completedOptions completedServerRunOptions, stopCh <-chan
}
}
// If additional API servers are added, they should be gated.
// If additional API servers are added, they should be gated.
apiExtensionsConfig
,
err
:=
createAPIExtensionsConfig
(
*
kubeAPIServerConfig
.
GenericConfig
,
kubeAPIServerConfig
.
ExtraConfig
.
VersionedInformers
,
pluginInitializer
,
completedOptions
.
ServerRunOptions
,
completedOptions
.
MasterCount
)
apiExtensionsConfig
,
err
:=
createAPIExtensionsConfig
(
*
kubeAPIServerConfig
.
GenericConfig
,
kubeAPIServerConfig
.
ExtraConfig
.
VersionedInformers
,
pluginInitializer
,
completedOptions
.
ServerRunOptions
,
completedOptions
.
MasterCount
,
serviceResolver
,
webhook
.
NewDefaultAuthenticationInfoResolverWrapper
(
proxyTransport
,
kubeAPIServerConfig
.
GenericConfig
.
LoopbackClientConfig
))
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
...
...
staging/src/k8s.io/apiextensions-apiserver/Godeps/Godeps.json
View file @
97baad34
...
@@ -2343,6 +2343,10 @@
...
@@ -2343,6 +2343,10 @@
"Rev"
:
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev"
:
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
},
{
{
"ImportPath"
:
"k8s.io/apimachinery/pkg/util/uuid"
,
"Rev"
:
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath"
:
"k8s.io/apimachinery/pkg/util/validation"
,
"ImportPath"
:
"k8s.io/apimachinery/pkg/util/validation"
,
"Rev"
:
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev"
:
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
},
...
@@ -2451,6 +2455,10 @@
...
@@ -2451,6 +2455,10 @@
"Rev"
:
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev"
:
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
},
{
{
"ImportPath"
:
"k8s.io/apiserver/pkg/util/proxy"
,
"Rev"
:
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath"
:
"k8s.io/apiserver/pkg/util/webhook"
,
"ImportPath"
:
"k8s.io/apiserver/pkg/util/webhook"
,
"Rev"
:
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev"
:
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
},
...
@@ -2475,6 +2483,10 @@
...
@@ -2475,6 +2483,10 @@
"Rev"
:
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev"
:
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
},
{
{
"ImportPath"
:
"k8s.io/client-go/listers/core/v1"
,
"Rev"
:
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
{
"ImportPath"
:
"k8s.io/client-go/rest"
,
"ImportPath"
:
"k8s.io/client-go/rest"
,
"Rev"
:
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev"
:
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
},
...
...
staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/BUILD
View file @
97baad34
...
@@ -67,6 +67,7 @@ go_library(
...
@@ -67,6 +67,7 @@ go_library(
"//staging/src/k8s.io/apiserver/pkg/server/storage:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/server/storage:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/storage/storagebackend:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/storage/storagebackend:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/webhook:go_default_library",
"//staging/src/k8s.io/client-go/scale:go_default_library",
"//staging/src/k8s.io/client-go/scale:go_default_library",
"//staging/src/k8s.io/client-go/scale/scheme/autoscalingv1:go_default_library",
"//staging/src/k8s.io/client-go/scale/scheme/autoscalingv1:go_default_library",
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
...
...
staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/apiserver.go
View file @
97baad34
...
@@ -31,6 +31,7 @@ import (
...
@@ -31,6 +31,7 @@ import (
"k8s.io/apiserver/pkg/registry/rest"
"k8s.io/apiserver/pkg/registry/rest"
genericapiserver
"k8s.io/apiserver/pkg/server"
genericapiserver
"k8s.io/apiserver/pkg/server"
serverstorage
"k8s.io/apiserver/pkg/server/storage"
serverstorage
"k8s.io/apiserver/pkg/server/storage"
"k8s.io/apiserver/pkg/util/webhook"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/install"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/install"
...
@@ -78,6 +79,11 @@ type ExtraConfig struct {
...
@@ -78,6 +79,11 @@ type ExtraConfig struct {
// MasterCount is used to detect whether cluster is HA, and if it is
// MasterCount is used to detect whether cluster is HA, and if it is
// the CRD Establishing will be hold by 5 seconds.
// the CRD Establishing will be hold by 5 seconds.
MasterCount
int
MasterCount
int
// ServiceResolver is used in CR webhook converters to resolve webhook's service names
ServiceResolver
webhook
.
ServiceResolver
// AuthResolverWrapper is used in CR webhook converters
AuthResolverWrapper
webhook
.
AuthenticationInfoResolverWrapper
}
}
type
Config
struct
{
type
Config
struct
{
...
@@ -167,7 +173,7 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget)
...
@@ -167,7 +173,7 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget)
delegate
:
delegateHandler
,
delegate
:
delegateHandler
,
}
}
establishingController
:=
establish
.
NewEstablishingController
(
s
.
Informers
.
Apiextensions
()
.
InternalVersion
()
.
CustomResourceDefinitions
(),
crdClient
.
Apiextensions
())
establishingController
:=
establish
.
NewEstablishingController
(
s
.
Informers
.
Apiextensions
()
.
InternalVersion
()
.
CustomResourceDefinitions
(),
crdClient
.
Apiextensions
())
crdHandler
:=
NewCustomResourceDefinitionHandler
(
crdHandler
,
err
:=
NewCustomResourceDefinitionHandler
(
versionDiscoveryHandler
,
versionDiscoveryHandler
,
groupDiscoveryHandler
,
groupDiscoveryHandler
,
s
.
Informers
.
Apiextensions
()
.
InternalVersion
()
.
CustomResourceDefinitions
(),
s
.
Informers
.
Apiextensions
()
.
InternalVersion
()
.
CustomResourceDefinitions
(),
...
@@ -175,8 +181,13 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget)
...
@@ -175,8 +181,13 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget)
c
.
ExtraConfig
.
CRDRESTOptionsGetter
,
c
.
ExtraConfig
.
CRDRESTOptionsGetter
,
c
.
GenericConfig
.
AdmissionControl
,
c
.
GenericConfig
.
AdmissionControl
,
establishingController
,
establishingController
,
c
.
ExtraConfig
.
ServiceResolver
,
c
.
ExtraConfig
.
AuthResolverWrapper
,
c
.
ExtraConfig
.
MasterCount
,
c
.
ExtraConfig
.
MasterCount
,
)
)
if
err
!=
nil
{
return
nil
,
err
}
s
.
GenericAPIServer
.
Handler
.
NonGoRestfulMux
.
Handle
(
"/apis"
,
crdHandler
)
s
.
GenericAPIServer
.
Handler
.
NonGoRestfulMux
.
Handle
(
"/apis"
,
crdHandler
)
s
.
GenericAPIServer
.
Handler
.
NonGoRestfulMux
.
HandlePrefix
(
"/apis/"
,
crdHandler
)
s
.
GenericAPIServer
.
Handler
.
NonGoRestfulMux
.
HandlePrefix
(
"/apis/"
,
crdHandler
)
...
...
staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/conversion/BUILD
View file @
97baad34
...
@@ -5,15 +5,23 @@ go_library(
...
@@ -5,15 +5,23 @@ go_library(
srcs = [
srcs = [
"converter.go",
"converter.go",
"nop_converter.go",
"nop_converter.go",
"webhook_converter.go",
],
],
importmap = "k8s.io/kubernetes/vendor/k8s.io/apiextensions-apiserver/pkg/apiserver/conversion",
importmap = "k8s.io/kubernetes/vendor/k8s.io/apiextensions-apiserver/pkg/apiserver/conversion",
importpath = "k8s.io/apiextensions-apiserver/pkg/apiserver/conversion",
importpath = "k8s.io/apiextensions-apiserver/pkg/apiserver/conversion",
visibility = ["//visibility:public"],
visibility = ["//visibility:public"],
deps = [
deps = [
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/pkg/features:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_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/uuid:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/webhook:go_default_library",
"//staging/src/k8s.io/client-go/rest:go_default_library",
],
],
)
)
...
...
staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/conversion/converter.go
View file @
97baad34
...
@@ -20,39 +20,74 @@ import (
...
@@ -20,39 +20,74 @@ import (
"fmt"
"fmt"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
apiextensionsfeatures
"k8s.io/apiextensions-apiserver/pkg/features"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/schema"
utilfeature
"k8s.io/apiserver/pkg/util/feature"
"k8s.io/apiserver/pkg/util/webhook"
)
)
// NewCRDConverter returns a new CRD converter based on the conversion settings in crd object.
// CRConverterFactory is the factory for all CR converters.
func
NewCRDConverter
(
crd
*
apiextensions
.
CustomResourceDefinition
)
(
safe
,
unsafe
runtime
.
ObjectConvertor
)
{
type
CRConverterFactory
struct
{
// webhookConverterFactory is the factory for webhook converters.
// This field should not be used if CustomResourceWebhookConversion feature is disabled.
webhookConverterFactory
*
webhookConverterFactory
}
// NewCRConverterFactory creates a new CRConverterFactory
func
NewCRConverterFactory
(
serviceResolver
webhook
.
ServiceResolver
,
authResolverWrapper
webhook
.
AuthenticationInfoResolverWrapper
)
(
*
CRConverterFactory
,
error
)
{
converterFactory
:=
&
CRConverterFactory
{}
if
utilfeature
.
DefaultFeatureGate
.
Enabled
(
apiextensionsfeatures
.
CustomResourceWebhookConversion
)
{
webhookConverterFactory
,
err
:=
newWebhookConverterFactory
(
serviceResolver
,
authResolverWrapper
)
if
err
!=
nil
{
return
nil
,
err
}
converterFactory
.
webhookConverterFactory
=
webhookConverterFactory
}
return
converterFactory
,
nil
}
// NewConverter returns a new CR converter based on the conversion settings in crd object.
func
(
m
*
CRConverterFactory
)
NewConverter
(
crd
*
apiextensions
.
CustomResourceDefinition
)
(
safe
,
unsafe
runtime
.
ObjectConvertor
,
err
error
)
{
validVersions
:=
map
[
schema
.
GroupVersion
]
bool
{}
validVersions
:=
map
[
schema
.
GroupVersion
]
bool
{}
for
_
,
version
:=
range
crd
.
Spec
.
Versions
{
for
_
,
version
:=
range
crd
.
Spec
.
Versions
{
validVersions
[
schema
.
GroupVersion
{
Group
:
crd
.
Spec
.
Group
,
Version
:
version
.
Name
}]
=
true
validVersions
[
schema
.
GroupVersion
{
Group
:
crd
.
Spec
.
Group
,
Version
:
version
.
Name
}]
=
true
}
}
// The only converter right now is nopConverter. More converters will be returned based on the
switch
crd
.
Spec
.
Conversion
.
Strategy
{
// CRD object when they introduced.
case
apiextensions
.
NoneConverter
:
unsafe
=
&
crd
Converter
{
unsafe
=
&
cr
Converter
{
clusterScoped
:
crd
.
Spec
.
Scope
==
apiextensions
.
ClusterScoped
,
clusterScoped
:
crd
.
Spec
.
Scope
==
apiextensions
.
ClusterScoped
,
delegate
:
&
nopConverter
{
delegate
:
&
nopConverter
{
validVersions
:
validVersions
,
validVersions
:
validVersions
,
},
},
}
}
return
&
safeConverterWrapper
{
unsafe
},
unsafe
return
&
safeConverterWrapper
{
unsafe
},
unsafe
,
nil
case
apiextensions
.
WebhookConverter
:
if
!
utilfeature
.
DefaultFeatureGate
.
Enabled
(
apiextensionsfeatures
.
CustomResourceWebhookConversion
)
{
return
nil
,
nil
,
fmt
.
Errorf
(
"webhook conversion is disabled on this cluster"
)
}
unsafe
,
err
:=
m
.
webhookConverterFactory
.
NewWebhookConverter
(
validVersions
,
crd
)
if
err
!=
nil
{
return
nil
,
nil
,
err
}
return
&
safeConverterWrapper
{
unsafe
},
unsafe
,
nil
}
return
nil
,
nil
,
fmt
.
Errorf
(
"unknown conversion strategy %q for CRD %s"
,
crd
.
Spec
.
Conversion
.
Strategy
,
crd
.
Name
)
}
}
var
_
runtime
.
ObjectConvertor
=
&
cr
d
Converter
{}
var
_
runtime
.
ObjectConvertor
=
&
crConverter
{}
// cr
dConverter extends the delegate with generic CRD
conversion behaviour. The delegate will implement the
// cr
Converter extends the delegate with generic CR
conversion behaviour. The delegate will implement the
// user defined conversion strategy given in the CustomResourceDefinition.
// user defined conversion strategy given in the CustomResourceDefinition.
type
cr
d
Converter
struct
{
type
crConverter
struct
{
delegate
runtime
.
ObjectConvertor
delegate
runtime
.
ObjectConvertor
clusterScoped
bool
clusterScoped
bool
}
}
func
(
c
*
cr
d
Converter
)
ConvertFieldLabel
(
gvk
schema
.
GroupVersionKind
,
label
,
value
string
)
(
string
,
string
,
error
)
{
func
(
c
*
crConverter
)
ConvertFieldLabel
(
gvk
schema
.
GroupVersionKind
,
label
,
value
string
)
(
string
,
string
,
error
)
{
// We currently only support metadata.namespace and metadata.name.
// We currently only support metadata.namespace and metadata.name.
switch
{
switch
{
case
label
==
"metadata.name"
:
case
label
==
"metadata.name"
:
...
@@ -64,12 +99,12 @@ func (c *crdConverter) ConvertFieldLabel(gvk schema.GroupVersionKind, label, val
...
@@ -64,12 +99,12 @@ func (c *crdConverter) ConvertFieldLabel(gvk schema.GroupVersionKind, label, val
}
}
}
}
func
(
c
*
cr
d
Converter
)
Convert
(
in
,
out
,
context
interface
{})
error
{
func
(
c
*
crConverter
)
Convert
(
in
,
out
,
context
interface
{})
error
{
return
c
.
delegate
.
Convert
(
in
,
out
,
context
)
return
c
.
delegate
.
Convert
(
in
,
out
,
context
)
}
}
// ConvertToVersion converts in object to the given gvk in place and returns the same `in` object.
// ConvertToVersion converts in object to the given gvk in place and returns the same `in` object.
func
(
c
*
cr
d
Converter
)
ConvertToVersion
(
in
runtime
.
Object
,
target
runtime
.
GroupVersioner
)
(
runtime
.
Object
,
error
)
{
func
(
c
*
crConverter
)
ConvertToVersion
(
in
runtime
.
Object
,
target
runtime
.
GroupVersioner
)
(
runtime
.
Object
,
error
)
{
// Run the converter on the list items instead of list itself
// Run the converter on the list items instead of list itself
if
list
,
ok
:=
in
.
(
*
unstructured
.
UnstructuredList
);
ok
{
if
list
,
ok
:=
in
.
(
*
unstructured
.
UnstructuredList
);
ok
{
for
i
:=
range
list
.
Items
{
for
i
:=
range
list
.
Items
{
...
...
staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/conversion/nop_converter.go
View file @
97baad34
...
@@ -49,11 +49,11 @@ func (c *nopConverter) Convert(in, out, context interface{}) error {
...
@@ -49,11 +49,11 @@ func (c *nopConverter) Convert(in, out, context interface{}) error {
outGVK
:=
unstructOut
.
GroupVersionKind
()
outGVK
:=
unstructOut
.
GroupVersionKind
()
if
!
c
.
validVersions
[
outGVK
.
GroupVersion
()]
{
if
!
c
.
validVersions
[
outGVK
.
GroupVersion
()]
{
return
fmt
.
Errorf
(
"request to convert CR
D
from an invalid group/version: %s"
,
outGVK
.
String
())
return
fmt
.
Errorf
(
"request to convert CR from an invalid group/version: %s"
,
outGVK
.
String
())
}
}
inGVK
:=
unstructIn
.
GroupVersionKind
()
inGVK
:=
unstructIn
.
GroupVersionKind
()
if
!
c
.
validVersions
[
inGVK
.
GroupVersion
()]
{
if
!
c
.
validVersions
[
inGVK
.
GroupVersion
()]
{
return
fmt
.
Errorf
(
"request to convert CR
D
to an invalid group/version: %s"
,
inGVK
.
String
())
return
fmt
.
Errorf
(
"request to convert CR to an invalid group/version: %s"
,
inGVK
.
String
())
}
}
unstructOut
.
SetUnstructuredContent
(
unstructIn
.
UnstructuredContent
())
unstructOut
.
SetUnstructuredContent
(
unstructIn
.
UnstructuredContent
())
...
@@ -72,7 +72,7 @@ func (c *nopConverter) ConvertToVersion(in runtime.Object, target runtime.GroupV
...
@@ -72,7 +72,7 @@ func (c *nopConverter) ConvertToVersion(in runtime.Object, target runtime.GroupV
return
nil
,
fmt
.
Errorf
(
"%v is unstructured and is not suitable for converting to %q"
,
kind
,
target
)
return
nil
,
fmt
.
Errorf
(
"%v is unstructured and is not suitable for converting to %q"
,
kind
,
target
)
}
}
if
!
c
.
validVersions
[
gvk
.
GroupVersion
()]
{
if
!
c
.
validVersions
[
gvk
.
GroupVersion
()]
{
return
nil
,
fmt
.
Errorf
(
"request to convert CR
D
to an invalid group/version: %s"
,
gvk
.
String
())
return
nil
,
fmt
.
Errorf
(
"request to convert CR to an invalid group/version: %s"
,
gvk
.
String
())
}
}
in
.
GetObjectKind
()
.
SetGroupVersionKind
(
gvk
)
in
.
GetObjectKind
()
.
SetGroupVersionKind
(
gvk
)
return
in
,
nil
return
in
,
nil
...
...
staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/conversion/webhook_converter.go
0 → 100644
View file @
97baad34
This diff is collapsed.
Click to expand it.
staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go
View file @
97baad34
...
@@ -67,6 +67,7 @@ import (
...
@@ -67,6 +67,7 @@ import (
apiextensionsfeatures
"k8s.io/apiextensions-apiserver/pkg/features"
apiextensionsfeatures
"k8s.io/apiextensions-apiserver/pkg/features"
"k8s.io/apiextensions-apiserver/pkg/registry/customresource"
"k8s.io/apiextensions-apiserver/pkg/registry/customresource"
"k8s.io/apiextensions-apiserver/pkg/registry/customresource/tableconvertor"
"k8s.io/apiextensions-apiserver/pkg/registry/customresource/tableconvertor"
"k8s.io/apiserver/pkg/util/webhook"
)
)
// crdHandler serves the `/apis` endpoint.
// crdHandler serves the `/apis` endpoint.
...
@@ -93,6 +94,8 @@ type crdHandler struct {
...
@@ -93,6 +94,8 @@ type crdHandler struct {
// MasterCount is used to implement sleep to improve
// MasterCount is used to implement sleep to improve
// CRD establishing process for HA clusters.
// CRD establishing process for HA clusters.
masterCount
int
masterCount
int
converterFactory
*
conversion
.
CRConverterFactory
}
}
// crdInfo stores enough information to serve the storage for the custom resource
// crdInfo stores enough information to serve the storage for the custom resource
...
@@ -129,7 +132,9 @@ func NewCustomResourceDefinitionHandler(
...
@@ -129,7 +132,9 @@ func NewCustomResourceDefinitionHandler(
restOptionsGetter
generic
.
RESTOptionsGetter
,
restOptionsGetter
generic
.
RESTOptionsGetter
,
admission
admission
.
Interface
,
admission
admission
.
Interface
,
establishingController
*
establish
.
EstablishingController
,
establishingController
*
establish
.
EstablishingController
,
masterCount
int
)
*
crdHandler
{
serviceResolver
webhook
.
ServiceResolver
,
authResolverWrapper
webhook
.
AuthenticationInfoResolverWrapper
,
masterCount
int
)
(
*
crdHandler
,
error
)
{
ret
:=
&
crdHandler
{
ret
:=
&
crdHandler
{
versionDiscoveryHandler
:
versionDiscoveryHandler
,
versionDiscoveryHandler
:
versionDiscoveryHandler
,
groupDiscoveryHandler
:
groupDiscoveryHandler
,
groupDiscoveryHandler
:
groupDiscoveryHandler
,
...
@@ -147,10 +152,15 @@ func NewCustomResourceDefinitionHandler(
...
@@ -147,10 +152,15 @@ func NewCustomResourceDefinitionHandler(
ret
.
removeDeadStorage
()
ret
.
removeDeadStorage
()
},
},
})
})
crConverterFactory
,
err
:=
conversion
.
NewCRConverterFactory
(
serviceResolver
,
authResolverWrapper
)
if
err
!=
nil
{
return
nil
,
err
}
ret
.
converterFactory
=
crConverterFactory
ret
.
customStorage
.
Store
(
crdStorageMap
{})
ret
.
customStorage
.
Store
(
crdStorageMap
{})
return
ret
return
ret
,
nil
}
}
func
(
r
*
crdHandler
)
ServeHTTP
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
func
(
r
*
crdHandler
)
ServeHTTP
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
...
@@ -433,7 +443,10 @@ func (r *crdHandler) getOrCreateServingInfoFor(crd *apiextensions.CustomResource
...
@@ -433,7 +443,10 @@ func (r *crdHandler) getOrCreateServingInfoFor(crd *apiextensions.CustomResource
scaleScopes
:=
map
[
string
]
handlers
.
RequestScope
{}
scaleScopes
:=
map
[
string
]
handlers
.
RequestScope
{}
for
_
,
v
:=
range
crd
.
Spec
.
Versions
{
for
_
,
v
:=
range
crd
.
Spec
.
Versions
{
safeConverter
,
unsafeConverter
:=
conversion
.
NewCRDConverter
(
crd
)
safeConverter
,
unsafeConverter
,
err
:=
r
.
converterFactory
.
NewConverter
(
crd
)
if
err
!=
nil
{
return
nil
,
err
}
// In addition to Unstructured objects (Custom Resources), we also may sometimes need to
// In addition to Unstructured objects (Custom Resources), we also may sometimes need to
// decode unversioned Options objects, so we delegate to parameterScheme for such types.
// decode unversioned Options objects, so we delegate to parameterScheme for such types.
parameterScheme
:=
runtime
.
NewScheme
()
parameterScheme
:=
runtime
.
NewScheme
()
...
...
staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler_test.go
View file @
97baad34
...
@@ -79,14 +79,24 @@ func TestConvertFieldLabel(t *testing.T) {
...
@@ -79,14 +79,24 @@ func TestConvertFieldLabel(t *testing.T) {
for
_
,
test
:=
range
tests
{
for
_
,
test
:=
range
tests
{
t
.
Run
(
test
.
name
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
test
.
name
,
func
(
t
*
testing
.
T
)
{
crd
:=
apiextensions
.
CustomResourceDefinition
{}
crd
:=
apiextensions
.
CustomResourceDefinition
{
Spec
:
apiextensions
.
CustomResourceDefinitionSpec
{
Conversion
:
&
apiextensions
.
CustomResourceConversion
{
Strategy
:
"None"
,
},
},
}
if
test
.
clusterScoped
{
if
test
.
clusterScoped
{
crd
.
Spec
.
Scope
=
apiextensions
.
ClusterScoped
crd
.
Spec
.
Scope
=
apiextensions
.
ClusterScoped
}
else
{
}
else
{
crd
.
Spec
.
Scope
=
apiextensions
.
NamespaceScoped
crd
.
Spec
.
Scope
=
apiextensions
.
NamespaceScoped
}
}
_
,
c
:=
conversion
.
NewCRDConverter
(
&
crd
)
f
,
err
:=
conversion
.
NewCRConverterFactory
(
nil
,
nil
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
_
,
c
,
err
:=
f
.
NewConverter
(
&
crd
)
label
,
value
,
err
:=
c
.
ConvertFieldLabel
(
schema
.
GroupVersionKind
{},
test
.
label
,
"value"
)
label
,
value
,
err
:=
c
.
ConvertFieldLabel
(
schema
.
GroupVersionKind
{},
test
.
label
,
"value"
)
if
e
,
a
:=
test
.
expectError
,
err
!=
nil
;
e
!=
a
{
if
e
,
a
:=
test
.
expectError
,
err
!=
nil
;
e
!=
a
{
...
...
staging/src/k8s.io/apiextensions-apiserver/pkg/cmd/server/options/BUILD
View file @
97baad34
...
@@ -14,6 +14,9 @@ go_library(
...
@@ -14,6 +14,9 @@ go_library(
"//staging/src/k8s.io/apiserver/pkg/registry/generic:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/registry/generic:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/server:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/server:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/server/options:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/server/options:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/proxy:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/webhook:go_default_library",
"//staging/src/k8s.io/client-go/listers/core/v1:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
],
],
)
)
...
...
staging/src/k8s.io/apiextensions-apiserver/pkg/cmd/server/options/options.go
View file @
97baad34
...
@@ -20,6 +20,7 @@ import (
...
@@ -20,6 +20,7 @@ import (
"fmt"
"fmt"
"io"
"io"
"net"
"net"
"net/url"
"github.com/spf13/pflag"
"github.com/spf13/pflag"
...
@@ -30,6 +31,9 @@ import (
...
@@ -30,6 +31,9 @@ import (
genericregistry
"k8s.io/apiserver/pkg/registry/generic"
genericregistry
"k8s.io/apiserver/pkg/registry/generic"
genericapiserver
"k8s.io/apiserver/pkg/server"
genericapiserver
"k8s.io/apiserver/pkg/server"
genericoptions
"k8s.io/apiserver/pkg/server/options"
genericoptions
"k8s.io/apiserver/pkg/server/options"
"k8s.io/apiserver/pkg/util/proxy"
"k8s.io/apiserver/pkg/util/webhook"
"k8s.io/client-go/listers/core/v1"
)
)
const
defaultEtcdPathPrefix
=
"/registry/apiextensions.kubernetes.io"
const
defaultEtcdPathPrefix
=
"/registry/apiextensions.kubernetes.io"
...
@@ -94,6 +98,8 @@ func (o CustomResourceDefinitionsServerOptions) Config() (*apiserver.Config, err
...
@@ -94,6 +98,8 @@ func (o CustomResourceDefinitionsServerOptions) Config() (*apiserver.Config, err
GenericConfig
:
serverConfig
,
GenericConfig
:
serverConfig
,
ExtraConfig
:
apiserver
.
ExtraConfig
{
ExtraConfig
:
apiserver
.
ExtraConfig
{
CRDRESTOptionsGetter
:
NewCRDRESTOptionsGetter
(
*
o
.
RecommendedOptions
.
Etcd
),
CRDRESTOptionsGetter
:
NewCRDRESTOptionsGetter
(
*
o
.
RecommendedOptions
.
Etcd
),
ServiceResolver
:
&
serviceResolver
{
serverConfig
.
SharedInformerFactory
.
Core
()
.
V1
()
.
Services
()
.
Lister
()},
AuthResolverWrapper
:
webhook
.
NewDefaultAuthenticationInfoResolverWrapper
(
nil
,
serverConfig
.
LoopbackClientConfig
),
},
},
}
}
return
config
,
nil
return
config
,
nil
...
@@ -114,3 +120,11 @@ func NewCRDRESTOptionsGetter(etcdOptions genericoptions.EtcdOptions) genericregi
...
@@ -114,3 +120,11 @@ func NewCRDRESTOptionsGetter(etcdOptions genericoptions.EtcdOptions) genericregi
return
ret
return
ret
}
}
type
serviceResolver
struct
{
services
v1
.
ServiceLister
}
func
(
r
*
serviceResolver
)
ResolveEndpoint
(
namespace
,
name
string
)
(
*
url
.
URL
,
error
)
{
return
proxy
.
ResolveCluster
(
r
.
services
,
namespace
,
name
)
}
staging/src/k8s.io/apiextensions-apiserver/test/integration/helpers.go
View file @
97baad34
...
@@ -76,8 +76,8 @@ func newNamespacedCustomResourceClient(ns string, client dynamic.Interface, crd
...
@@ -76,8 +76,8 @@ func newNamespacedCustomResourceClient(ns string, client dynamic.Interface, crd
return
newNamespacedCustomResourceVersionedClient
(
ns
,
client
,
crd
,
crd
.
Spec
.
Versions
[
0
]
.
Name
)
return
newNamespacedCustomResourceVersionedClient
(
ns
,
client
,
crd
,
crd
.
Spec
.
Versions
[
0
]
.
Name
)
}
}
//
u
pdateCustomResourceDefinitionWithRetry updates a CRD, retrying up to 5 times on version conflict errors.
//
U
pdateCustomResourceDefinitionWithRetry updates a CRD, retrying up to 5 times on version conflict errors.
func
u
pdateCustomResourceDefinitionWithRetry
(
client
clientset
.
Interface
,
name
string
,
update
func
(
*
apiextensionsv1beta1
.
CustomResourceDefinition
))
(
*
apiextensionsv1beta1
.
CustomResourceDefinition
,
error
)
{
func
U
pdateCustomResourceDefinitionWithRetry
(
client
clientset
.
Interface
,
name
string
,
update
func
(
*
apiextensionsv1beta1
.
CustomResourceDefinition
))
(
*
apiextensionsv1beta1
.
CustomResourceDefinition
,
error
)
{
for
i
:=
0
;
i
<
5
;
i
++
{
for
i
:=
0
;
i
<
5
;
i
++
{
crd
,
err
:=
client
.
ApiextensionsV1beta1
()
.
CustomResourceDefinitions
()
.
Get
(
name
,
metav1
.
GetOptions
{})
crd
,
err
:=
client
.
ApiextensionsV1beta1
()
.
CustomResourceDefinitions
()
.
Get
(
name
,
metav1
.
GetOptions
{})
if
err
!=
nil
{
if
err
!=
nil
{
...
...
staging/src/k8s.io/apiextensions-apiserver/test/integration/validation_test.go
View file @
97baad34
...
@@ -445,7 +445,7 @@ func TestCRValidationOnCRDUpdate(t *testing.T) {
...
@@ -445,7 +445,7 @@ func TestCRValidationOnCRDUpdate(t *testing.T) {
}
}
// update the CRD to a less stricter schema
// update the CRD to a less stricter schema
_
,
err
=
u
pdateCustomResourceDefinitionWithRetry
(
apiExtensionClient
,
"noxus.mygroup.example.com"
,
func
(
crd
*
apiextensionsv1beta1
.
CustomResourceDefinition
)
{
_
,
err
=
U
pdateCustomResourceDefinitionWithRetry
(
apiExtensionClient
,
"noxus.mygroup.example.com"
,
func
(
crd
*
apiextensionsv1beta1
.
CustomResourceDefinition
)
{
validationSchema
,
err
:=
getSchemaForVersion
(
crd
,
v
.
Name
)
validationSchema
,
err
:=
getSchemaForVersion
(
crd
,
v
.
Name
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatal
(
err
)
t
.
Fatal
(
err
)
...
...
staging/src/k8s.io/apiextensions-apiserver/test/integration/versioning_test.go
View file @
97baad34
...
@@ -64,7 +64,7 @@ func TestInternalVersionIsHandlerVersion(t *testing.T) {
...
@@ -64,7 +64,7 @@ func TestInternalVersionIsHandlerVersion(t *testing.T) {
// update validation via update because the cache priming in CreateNewCustomResourceDefinition will fail otherwise
// update validation via update because the cache priming in CreateNewCustomResourceDefinition will fail otherwise
t
.
Logf
(
"Updating CRD to validate apiVersion"
)
t
.
Logf
(
"Updating CRD to validate apiVersion"
)
noxuDefinition
,
err
=
u
pdateCustomResourceDefinitionWithRetry
(
apiExtensionClient
,
noxuDefinition
.
Name
,
func
(
crd
*
apiextensionsv1beta1
.
CustomResourceDefinition
)
{
noxuDefinition
,
err
=
U
pdateCustomResourceDefinitionWithRetry
(
apiExtensionClient
,
noxuDefinition
.
Name
,
func
(
crd
*
apiextensionsv1beta1
.
CustomResourceDefinition
)
{
crd
.
Spec
.
Validation
=
&
apiextensionsv1beta1
.
CustomResourceValidation
{
crd
.
Spec
.
Validation
=
&
apiextensionsv1beta1
.
CustomResourceValidation
{
OpenAPIV3Schema
:
&
apiextensionsv1beta1
.
JSONSchemaProps
{
OpenAPIV3Schema
:
&
apiextensionsv1beta1
.
JSONSchemaProps
{
Properties
:
map
[
string
]
apiextensionsv1beta1
.
JSONSchemaProps
{
Properties
:
map
[
string
]
apiextensionsv1beta1
.
JSONSchemaProps
{
...
...
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/webhook.go
View file @
97baad34
...
@@ -164,6 +164,7 @@ func (a *Webhook) Dispatch(attr admission.Attributes) error {
...
@@ -164,6 +164,7 @@ func (a *Webhook) Dispatch(attr admission.Attributes) error {
return
admission
.
NewForbidden
(
attr
,
fmt
.
Errorf
(
"not yet ready to handle request"
))
return
admission
.
NewForbidden
(
attr
,
fmt
.
Errorf
(
"not yet ready to handle request"
))
}
}
hooks
:=
a
.
hookSource
.
Webhooks
()
hooks
:=
a
.
hookSource
.
Webhooks
()
// TODO: Figure out if adding one second timeout make sense here.
ctx
:=
context
.
TODO
()
ctx
:=
context
.
TODO
()
var
relevantHooks
[]
*
v1beta1
.
Webhook
var
relevantHooks
[]
*
v1beta1
.
Webhook
...
...
test/e2e/apimachinery/BUILD
View file @
97baad34
...
@@ -11,6 +11,7 @@ go_library(
...
@@ -11,6 +11,7 @@ go_library(
"aggregator.go",
"aggregator.go",
"certs.go",
"certs.go",
"chunking.go",
"chunking.go",
"crd_conversion_webhook.go",
"crd_watch.go",
"crd_watch.go",
"custom_resource_definition.go",
"custom_resource_definition.go",
"etcd_failure.go",
"etcd_failure.go",
...
@@ -36,9 +37,11 @@ go_library(
...
@@ -36,9 +37,11 @@ go_library(
"//staging/src/k8s.io/api/batch/v1beta1:go_default_library",
"//staging/src/k8s.io/api/batch/v1beta1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/extensions/v1beta1:go_default_library",
"//staging/src/k8s.io/api/extensions/v1beta1:go_default_library",
"//staging/src/k8s.io/api/rbac/v1:go_default_library",
"//staging/src/k8s.io/api/rbac/v1beta1:go_default_library",
"//staging/src/k8s.io/api/rbac/v1beta1:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/test/integration:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/test/integration/fixtures:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/test/integration/fixtures:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
...
...
test/e2e/apimachinery/crd_conversion_webhook.go
0 → 100644
View file @
97baad34
This diff is collapsed.
Click to expand it.
test/e2e/apimachinery/webhook.go
View file @
97baad34
...
@@ -136,7 +136,7 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
...
@@ -136,7 +136,7 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
defer
testcrd
.
CleanUp
()
defer
testcrd
.
CleanUp
()
webhookCleanup
:=
registerWebhookForCustomResource
(
f
,
context
,
testcrd
)
webhookCleanup
:=
registerWebhookForCustomResource
(
f
,
context
,
testcrd
)
defer
webhookCleanup
()
defer
webhookCleanup
()
testCustomResourceWebhook
(
f
,
testcrd
.
Crd
,
testcrd
.
DynamicClient
)
testCustomResourceWebhook
(
f
,
testcrd
.
Crd
,
testcrd
.
GetV1DynamicClient
()
)
})
})
It
(
"Should unconditionally reject operations on fail closed webhook"
,
func
()
{
It
(
"Should unconditionally reject operations on fail closed webhook"
,
func
()
{
...
@@ -173,7 +173,7 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
...
@@ -173,7 +173,7 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
defer
testcrd
.
CleanUp
()
defer
testcrd
.
CleanUp
()
webhookCleanup
:=
registerMutatingWebhookForCustomResource
(
f
,
context
,
testcrd
)
webhookCleanup
:=
registerMutatingWebhookForCustomResource
(
f
,
context
,
testcrd
)
defer
webhookCleanup
()
defer
webhookCleanup
()
testMutatingCustomResourceWebhook
(
f
,
testcrd
.
Crd
,
testcrd
.
DynamicClient
)
testMutatingCustomResourceWebhook
(
f
,
testcrd
.
Crd
,
testcrd
.
GetV1DynamicClient
()
)
})
})
It
(
"Should deny crd creation"
,
func
()
{
It
(
"Should deny crd creation"
,
func
()
{
...
@@ -1157,7 +1157,7 @@ func registerWebhookForCustomResource(f *framework.Framework, context *certConte
...
@@ -1157,7 +1157,7 @@ func registerWebhookForCustomResource(f *framework.Framework, context *certConte
Operations
:
[]
v1beta1
.
OperationType
{
v1beta1
.
Create
},
Operations
:
[]
v1beta1
.
OperationType
{
v1beta1
.
Create
},
Rule
:
v1beta1
.
Rule
{
Rule
:
v1beta1
.
Rule
{
APIGroups
:
[]
string
{
testcrd
.
ApiGroup
},
APIGroups
:
[]
string
{
testcrd
.
ApiGroup
},
APIVersions
:
[]
string
{
testcrd
.
ApiVersion
}
,
APIVersions
:
testcrd
.
GetAPIVersions
()
,
Resources
:
[]
string
{
testcrd
.
GetPluralName
()},
Resources
:
[]
string
{
testcrd
.
GetPluralName
()},
},
},
}},
}},
...
@@ -1198,7 +1198,7 @@ func registerMutatingWebhookForCustomResource(f *framework.Framework, context *c
...
@@ -1198,7 +1198,7 @@ func registerMutatingWebhookForCustomResource(f *framework.Framework, context *c
Operations
:
[]
v1beta1
.
OperationType
{
v1beta1
.
Create
},
Operations
:
[]
v1beta1
.
OperationType
{
v1beta1
.
Create
},
Rule
:
v1beta1
.
Rule
{
Rule
:
v1beta1
.
Rule
{
APIGroups
:
[]
string
{
testcrd
.
ApiGroup
},
APIGroups
:
[]
string
{
testcrd
.
ApiGroup
},
APIVersions
:
[]
string
{
testcrd
.
ApiVersion
}
,
APIVersions
:
testcrd
.
GetAPIVersions
()
,
Resources
:
[]
string
{
testcrd
.
GetPluralName
()},
Resources
:
[]
string
{
testcrd
.
GetPluralName
()},
},
},
}},
}},
...
@@ -1217,7 +1217,7 @@ func registerMutatingWebhookForCustomResource(f *framework.Framework, context *c
...
@@ -1217,7 +1217,7 @@ func registerMutatingWebhookForCustomResource(f *framework.Framework, context *c
Operations
:
[]
v1beta1
.
OperationType
{
v1beta1
.
Create
},
Operations
:
[]
v1beta1
.
OperationType
{
v1beta1
.
Create
},
Rule
:
v1beta1
.
Rule
{
Rule
:
v1beta1
.
Rule
{
APIGroups
:
[]
string
{
testcrd
.
ApiGroup
},
APIGroups
:
[]
string
{
testcrd
.
ApiGroup
},
APIVersions
:
[]
string
{
testcrd
.
ApiVersion
}
,
APIVersions
:
testcrd
.
GetAPIVersions
()
,
Resources
:
[]
string
{
testcrd
.
GetPluralName
()},
Resources
:
[]
string
{
testcrd
.
GetPluralName
()},
},
},
}},
}},
...
@@ -1343,12 +1343,18 @@ func testCRDDenyWebhook(f *framework.Framework) {
...
@@ -1343,12 +1343,18 @@ func testCRDDenyWebhook(f *framework.Framework) {
name
:=
fmt
.
Sprintf
(
"e2e-test-%s-%s-crd"
,
f
.
BaseName
,
"deny"
)
name
:=
fmt
.
Sprintf
(
"e2e-test-%s-%s-crd"
,
f
.
BaseName
,
"deny"
)
kind
:=
fmt
.
Sprintf
(
"E2e-test-%s-%s-crd"
,
f
.
BaseName
,
"deny"
)
kind
:=
fmt
.
Sprintf
(
"E2e-test-%s-%s-crd"
,
f
.
BaseName
,
"deny"
)
group
:=
fmt
.
Sprintf
(
"%s-crd-test.k8s.io"
,
f
.
BaseName
)
group
:=
fmt
.
Sprintf
(
"%s-crd-test.k8s.io"
,
f
.
BaseName
)
apiVersion
:=
"v1"
apiVersions
:=
[]
apiextensionsv1beta1
.
CustomResourceDefinitionVersion
{
{
Name
:
"v1"
,
Served
:
true
,
Storage
:
true
,
},
}
testcrd
:=
&
framework
.
TestCrd
{
testcrd
:=
&
framework
.
TestCrd
{
Name
:
name
,
Name
:
name
,
Kind
:
kind
,
Kind
:
kind
,
ApiGroup
:
group
,
ApiGroup
:
group
,
ApiVersion
:
apiVersion
,
Versions
:
apiVersions
,
}
}
// Creating a custom resource definition for use by assorted tests.
// Creating a custom resource definition for use by assorted tests.
...
@@ -1371,7 +1377,7 @@ func testCRDDenyWebhook(f *framework.Framework) {
...
@@ -1371,7 +1377,7 @@ func testCRDDenyWebhook(f *framework.Framework) {
},
},
Spec
:
apiextensionsv1beta1
.
CustomResourceDefinitionSpec
{
Spec
:
apiextensionsv1beta1
.
CustomResourceDefinitionSpec
{
Group
:
testcrd
.
ApiGroup
,
Group
:
testcrd
.
ApiGroup
,
Version
:
testcrd
.
ApiVersion
,
Version
s
:
testcrd
.
Versions
,
Names
:
apiextensionsv1beta1
.
CustomResourceDefinitionNames
{
Names
:
apiextensionsv1beta1
.
CustomResourceDefinitionNames
{
Plural
:
testcrd
.
GetPluralName
(),
Plural
:
testcrd
.
GetPluralName
(),
Singular
:
testcrd
.
Name
,
Singular
:
testcrd
.
Name
,
...
...
test/e2e/framework/crd_util.go
View file @
97baad34
...
@@ -35,25 +35,23 @@ type TestCrd struct {
...
@@ -35,25 +35,23 @@ type TestCrd struct {
Name
string
Name
string
Kind
string
Kind
string
ApiGroup
string
ApiGroup
string
ApiVersion
string
Versions
[]
apiextensionsv1beta1
.
CustomResourceDefinitionVersion
ApiExtensionClient
*
crdclientset
.
Clientset
ApiExtensionClient
*
crdclientset
.
Clientset
Crd
*
apiextensionsv1beta1
.
CustomResourceDefinition
Crd
*
apiextensionsv1beta1
.
CustomResourceDefinition
DynamicClient
dynamic
.
ResourceInterface
DynamicClient
s
map
[
string
]
dynamic
.
ResourceInterface
CleanUp
CleanCrdFn
CleanUp
CleanCrdFn
}
}
// CreateTestCRD creates a new CRD specifically for the calling test.
// CreateTestCRD creates a new CRD specifically for the calling test.
func
Create
TestCRD
(
f
*
Framework
)
(
*
TestCrd
,
error
)
{
func
Create
MultiVersionTestCRD
(
f
*
Framework
,
group
string
,
apiVersions
[]
apiextensionsv1beta1
.
CustomResourceDefinitionVersion
,
conversionWebhook
*
apiextensionsv1beta1
.
WebhookClientConfig
)
(
*
TestCrd
,
error
)
{
suffix
:=
randomSuffix
()
suffix
:=
randomSuffix
()
name
:=
fmt
.
Sprintf
(
"e2e-test-%s-%s-crd"
,
f
.
BaseName
,
suffix
)
name
:=
fmt
.
Sprintf
(
"e2e-test-%s-%s-crd"
,
f
.
BaseName
,
suffix
)
kind
:=
fmt
.
Sprintf
(
"E2e-test-%s-%s-crd"
,
f
.
BaseName
,
suffix
)
kind
:=
fmt
.
Sprintf
(
"E2e-test-%s-%s-crd"
,
f
.
BaseName
,
suffix
)
group
:=
fmt
.
Sprintf
(
"%s-crd-test.k8s.io"
,
f
.
BaseName
)
apiVersion
:=
"v1"
testcrd
:=
&
TestCrd
{
testcrd
:=
&
TestCrd
{
Name
:
name
,
Name
:
name
,
Kind
:
kind
,
Kind
:
kind
,
ApiGroup
:
group
,
ApiGroup
:
group
,
ApiVersion
:
apiVersion
,
Versions
:
apiVersions
,
}
}
// Creating a custom resource definition for use by assorted tests.
// Creating a custom resource definition for use by assorted tests.
...
@@ -75,6 +73,13 @@ func CreateTestCRD(f *Framework) (*TestCrd, error) {
...
@@ -75,6 +73,13 @@ func CreateTestCRD(f *Framework) (*TestCrd, error) {
crd
:=
newCRDForTest
(
testcrd
)
crd
:=
newCRDForTest
(
testcrd
)
if
conversionWebhook
!=
nil
{
crd
.
Spec
.
Conversion
=
&
apiextensionsv1beta1
.
CustomResourceConversion
{
Strategy
:
"Webhook"
,
WebhookClientConfig
:
conversionWebhook
,
}
}
//create CRD and waits for the resource to be recognized and available.
//create CRD and waits for the resource to be recognized and available.
crd
,
err
=
fixtures
.
CreateNewCustomResourceDefinitionWatchUnsafe
(
crd
,
apiExtensionClient
)
crd
,
err
=
fixtures
.
CreateNewCustomResourceDefinitionWatchUnsafe
(
crd
,
apiExtensionClient
)
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -82,12 +87,17 @@ func CreateTestCRD(f *Framework) (*TestCrd, error) {
...
@@ -82,12 +87,17 @@ func CreateTestCRD(f *Framework) (*TestCrd, error) {
return
nil
,
err
return
nil
,
err
}
}
gvr
:=
schema
.
GroupVersionResource
{
Group
:
crd
.
Spec
.
Group
,
Version
:
crd
.
Spec
.
Version
,
Resource
:
crd
.
Spec
.
Names
.
Plural
}
resourceClients
:=
map
[
string
]
dynamic
.
ResourceInterface
{}
resourceClient
:=
dynamicClient
.
Resource
(
gvr
)
.
Namespace
(
f
.
Namespace
.
Name
)
for
_
,
v
:=
range
crd
.
Spec
.
Versions
{
if
v
.
Served
{
gvr
:=
schema
.
GroupVersionResource
{
Group
:
crd
.
Spec
.
Group
,
Version
:
v
.
Name
,
Resource
:
crd
.
Spec
.
Names
.
Plural
}
resourceClients
[
v
.
Name
]
=
dynamicClient
.
Resource
(
gvr
)
.
Namespace
(
f
.
Namespace
.
Name
)
}
}
testcrd
.
ApiExtensionClient
=
apiExtensionClient
testcrd
.
ApiExtensionClient
=
apiExtensionClient
testcrd
.
Crd
=
crd
testcrd
.
Crd
=
crd
testcrd
.
DynamicClient
=
resourceClient
testcrd
.
DynamicClient
s
=
resourceClients
testcrd
.
CleanUp
=
func
()
error
{
testcrd
.
CleanUp
=
func
()
error
{
err
:=
fixtures
.
DeleteCustomResourceDefinition
(
crd
,
apiExtensionClient
)
err
:=
fixtures
.
DeleteCustomResourceDefinition
(
crd
,
apiExtensionClient
)
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -98,13 +108,26 @@ func CreateTestCRD(f *Framework) (*TestCrd, error) {
...
@@ -98,13 +108,26 @@ func CreateTestCRD(f *Framework) (*TestCrd, error) {
return
testcrd
,
nil
return
testcrd
,
nil
}
}
// CreateTestCRD creates a new CRD specifically for the calling test.
func
CreateTestCRD
(
f
*
Framework
)
(
*
TestCrd
,
error
)
{
group
:=
fmt
.
Sprintf
(
"%s-crd-test.k8s.io"
,
f
.
BaseName
)
apiVersions
:=
[]
apiextensionsv1beta1
.
CustomResourceDefinitionVersion
{
{
Name
:
"v1"
,
Served
:
true
,
Storage
:
true
,
},
}
return
CreateMultiVersionTestCRD
(
f
,
group
,
apiVersions
,
nil
)
}
// newCRDForTest generates a CRD definition for the test
// newCRDForTest generates a CRD definition for the test
func
newCRDForTest
(
testcrd
*
TestCrd
)
*
apiextensionsv1beta1
.
CustomResourceDefinition
{
func
newCRDForTest
(
testcrd
*
TestCrd
)
*
apiextensionsv1beta1
.
CustomResourceDefinition
{
return
&
apiextensionsv1beta1
.
CustomResourceDefinition
{
return
&
apiextensionsv1beta1
.
CustomResourceDefinition
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
testcrd
.
GetMetaName
()},
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
testcrd
.
GetMetaName
()},
Spec
:
apiextensionsv1beta1
.
CustomResourceDefinitionSpec
{
Spec
:
apiextensionsv1beta1
.
CustomResourceDefinitionSpec
{
Group
:
testcrd
.
ApiGroup
,
Group
:
testcrd
.
ApiGroup
,
Version
:
testcrd
.
ApiVersion
,
Version
s
:
testcrd
.
Versions
,
Names
:
apiextensionsv1beta1
.
CustomResourceDefinitionNames
{
Names
:
apiextensionsv1beta1
.
CustomResourceDefinitionNames
{
Plural
:
testcrd
.
GetPluralName
(),
Plural
:
testcrd
.
GetPluralName
(),
Singular
:
testcrd
.
Name
,
Singular
:
testcrd
.
Name
,
...
@@ -130,3 +153,17 @@ func (c *TestCrd) GetPluralName() string {
...
@@ -130,3 +153,17 @@ func (c *TestCrd) GetPluralName() string {
func
(
c
*
TestCrd
)
GetListName
()
string
{
func
(
c
*
TestCrd
)
GetListName
()
string
{
return
c
.
Name
+
"List"
return
c
.
Name
+
"List"
}
}
func
(
c
*
TestCrd
)
GetAPIVersions
()
[]
string
{
ret
:=
[]
string
{}
for
_
,
v
:=
range
c
.
Versions
{
if
v
.
Served
{
ret
=
append
(
ret
,
v
.
Name
)
}
}
return
ret
}
func
(
c
*
TestCrd
)
GetV1DynamicClient
()
dynamic
.
ResourceInterface
{
return
c
.
DynamicClients
[
"v1"
]
}
test/images/BUILD
View file @
97baad34
...
@@ -12,6 +12,7 @@ filegroup(
...
@@ -12,6 +12,7 @@ filegroup(
srcs = [
srcs = [
":package-srcs",
":package-srcs",
"//test/images/apparmor-loader:all-srcs",
"//test/images/apparmor-loader:all-srcs",
"//test/images/crd-conversion-webhook:all-srcs",
"//test/images/echoserver:all-srcs",
"//test/images/echoserver:all-srcs",
"//test/images/entrypoint-tester:all-srcs",
"//test/images/entrypoint-tester:all-srcs",
"//test/images/fakegitserver:all-srcs",
"//test/images/fakegitserver:all-srcs",
...
...
test/images/crd-conversion-webhook/BASEIMAGE
0 → 100644
View file @
97baad34
amd64=alpine:3.6
arm=arm32v6/alpine:3.6
arm64=arm64v8/alpine:3.6
ppc64le=ppc64le/alpine:3.6
test/images/crd-conversion-webhook/BUILD
0 → 100644
View file @
97baad34
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "go_default_library",
srcs = [
"config.go",
"main.go",
],
importpath = "k8s.io/kubernetes/test/images/crd-conversion-webhook",
visibility = ["//visibility:private"],
deps = [
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/client-go/rest:go_default_library",
"//test/images/crd-conversion-webhook/converter:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
],
)
go_binary(
name = "crd-conversion-webhook",
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//test/images/crd-conversion-webhook/converter:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
test/images/crd-conversion-webhook/Dockerfile
0 → 100644
View file @
97baad34
# 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.
FROM
BASEIMAGE
ADD
crd_conversion_webhook /crd_conversion_webhook
ENTRYPOINT
["/crd_conversion_webhook"]
test/images/crd-conversion-webhook/Makefile
0 → 100644
View file @
97baad34
# 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.
SRCS
=
crd_conversion_webhook
ARCH
?=
amd64
TARGET
?=
$(CURDIR)
GOLANG_VERSION
?=
latest
SRC_DIR
=
$
(
notdir
$(
shell
pwd
)
)
export
bin
:
../image-util.sh bin
$(SRCS)
.PHONY
:
bin
test/images/crd-conversion-webhook/README.md
0 → 100644
View file @
97baad34
# Kubernetes External Admission Webhook Test Image
The image tests CustomResourceConversionWebhook. After deploying it to kubernetes cluster,
administrator needs to create a CustomResourceConversion.Webhook
in kubernetes cluster to use remote webhook for conversions.
## Build the code
```
bash
make build
```
test/images/crd-conversion-webhook/VERSION
0 → 100644
View file @
97baad34
1.13rev2
test/images/crd-conversion-webhook/config.go
0 → 100644
View file @
97baad34
/*
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
main
import
(
"crypto/tls"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"github.com/golang/glog"
)
// Get a clientset with in-cluster config.
func
getClient
()
*
kubernetes
.
Clientset
{
config
,
err
:=
rest
.
InClusterConfig
()
if
err
!=
nil
{
glog
.
Fatal
(
err
)
}
clientset
,
err
:=
kubernetes
.
NewForConfig
(
config
)
if
err
!=
nil
{
glog
.
Fatal
(
err
)
}
return
clientset
}
func
configTLS
(
config
Config
,
clientset
*
kubernetes
.
Clientset
)
*
tls
.
Config
{
sCert
,
err
:=
tls
.
LoadX509KeyPair
(
config
.
CertFile
,
config
.
KeyFile
)
if
err
!=
nil
{
glog
.
Fatal
(
err
)
}
return
&
tls
.
Config
{
Certificates
:
[]
tls
.
Certificate
{
sCert
},
// TODO: uses mutual tls after we agree on what cert the apiserver should use.
// ClientAuth: tls.RequireAndVerifyClientCert,
}
}
test/images/crd-conversion-webhook/converter/BUILD
0 → 100644
View file @
97baad34
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"example_converter.go",
"framework.go",
],
importpath = "k8s.io/kubernetes/test/images/crd-conversion-webhook/converter",
visibility = ["//visibility:public"],
deps = [
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json:go_default_library",
"//vendor/bitbucket.org/ww/goautoneg:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["converter_test.go"],
embed = [":go_default_library"],
deps = [
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
test/images/crd-conversion-webhook/converter/converter_test.go
0 → 100644
View file @
97baad34
/*
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
converter
import
(
"net/http"
"net/http/httptest"
"strings"
"testing"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer/json"
)
func
TestConverter
(
t
*
testing
.
T
)
{
sampleObj
:=
`kind: ConversionReview
apiVersion: apiextensions.k8s.io/v1beta1
request:
uid: 0000-0000-0000-0000
desiredAPIVersion: stable.example.com/v2
objects:
- apiVersion: stable.example.com/v1
kind: CronTab
metadata:
name: my-new-cron-object
spec:
cronSpec: "* * * * */5"
image: my-awesome-cron-image
hostPort: "localhost:7070"
`
// First try json, it should fail as the data is taml
response
:=
httptest
.
NewRecorder
()
request
,
err
:=
http
.
NewRequest
(
"POST"
,
"/convert"
,
strings
.
NewReader
(
sampleObj
))
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
request
.
Header
.
Add
(
"Content-Type"
,
"application/json"
)
ServeExampleConvert
(
response
,
request
)
convertReview
:=
v1beta1
.
ConversionReview
{}
scheme
:=
runtime
.
NewScheme
()
jsonSerializer
:=
json
.
NewSerializer
(
json
.
DefaultMetaFactory
,
scheme
,
scheme
,
false
)
if
_
,
_
,
err
:=
jsonSerializer
.
Decode
(
response
.
Body
.
Bytes
(),
nil
,
&
convertReview
);
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
convertReview
.
Response
.
Result
.
Status
!=
v1
.
StatusFailure
{
t
.
Fatalf
(
"expected the operation to fail when yaml is provided with json header"
)
}
else
if
!
strings
.
Contains
(
convertReview
.
Response
.
Result
.
Message
,
"json parse error"
)
{
t
.
Fatalf
(
"expected to fail on json parser, but it failed with: %v"
,
convertReview
.
Response
.
Result
.
Message
)
}
// Now try yaml, and it should successfully convert
response
=
httptest
.
NewRecorder
()
request
,
err
=
http
.
NewRequest
(
"POST"
,
"/convert"
,
strings
.
NewReader
(
sampleObj
))
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
request
.
Header
.
Add
(
"Content-Type"
,
"application/yaml"
)
ServeExampleConvert
(
response
,
request
)
convertReview
=
v1beta1
.
ConversionReview
{}
yamlSerializer
:=
json
.
NewYAMLSerializer
(
json
.
DefaultMetaFactory
,
scheme
,
scheme
)
if
_
,
_
,
err
:=
yamlSerializer
.
Decode
(
response
.
Body
.
Bytes
(),
nil
,
&
convertReview
);
err
!=
nil
{
t
.
Fatalf
(
"cannot decode data:
\n
%v
\n
Error: %v"
,
response
.
Body
,
err
)
}
if
convertReview
.
Response
.
Result
.
Status
!=
v1
.
StatusSuccess
{
t
.
Fatalf
(
"cr conversion failed: %v"
,
convertReview
.
Response
)
}
convertedObj
:=
unstructured
.
Unstructured
{}
if
_
,
_
,
err
:=
yamlSerializer
.
Decode
(
convertReview
.
Response
.
ConvertedObjects
[
0
]
.
Raw
,
nil
,
&
convertedObj
);
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
e
,
a
:=
"stable.example.com/v2"
,
convertedObj
.
GetAPIVersion
();
e
!=
a
{
t
.
Errorf
(
"expected= %v, actual= %v"
,
e
,
a
)
}
if
e
,
a
:=
"localhost"
,
convertedObj
.
Object
[
"host"
];
e
!=
a
{
t
.
Errorf
(
"expected= %v, actual= %v"
,
e
,
a
)
}
if
e
,
a
:=
"7070"
,
convertedObj
.
Object
[
"port"
];
e
!=
a
{
t
.
Errorf
(
"expected= %v, actual= %v"
,
e
,
a
)
}
}
test/images/crd-conversion-webhook/converter/example_converter.go
0 → 100644
View file @
97baad34
/*
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
converter
import
(
"fmt"
"strings"
"github.com/golang/glog"
metav1
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
func
convertExampleCRD
(
Object
*
unstructured
.
Unstructured
,
toVersion
string
)
(
*
unstructured
.
Unstructured
,
metav1
.
Status
)
{
glog
.
V
(
2
)
.
Info
(
"converting crd"
)
convertedObject
:=
Object
.
DeepCopy
()
fromVersion
:=
Object
.
GetAPIVersion
()
if
toVersion
==
fromVersion
{
return
nil
,
statusErrorWithMessage
(
"conversion from a version to itself should not call the webhook: %s"
,
toVersion
)
}
switch
Object
.
GetAPIVersion
()
{
case
"stable.example.com/v1"
:
switch
toVersion
{
case
"stable.example.com/v2"
:
hostPort
,
ok
:=
convertedObject
.
Object
[
"hostPort"
]
if
ok
{
delete
(
convertedObject
.
Object
,
"hostPort"
)
parts
:=
strings
.
Split
(
hostPort
.
(
string
),
":"
)
if
len
(
parts
)
!=
2
{
return
nil
,
statusErrorWithMessage
(
"invalid hostPort value `%v`"
,
hostPort
)
}
convertedObject
.
Object
[
"host"
]
=
parts
[
0
]
convertedObject
.
Object
[
"port"
]
=
parts
[
1
]
}
default
:
return
nil
,
statusErrorWithMessage
(
"unexpected conversion version %q"
,
toVersion
)
}
case
"stable.example.com/v2"
:
switch
toVersion
{
case
"stable.example.com/v1"
:
host
,
hasHost
:=
convertedObject
.
Object
[
"host"
]
port
,
hasPort
:=
convertedObject
.
Object
[
"port"
]
if
hasHost
||
hasPort
{
if
!
hasHost
{
host
=
""
}
if
!
hasPort
{
port
=
""
}
convertedObject
.
Object
[
"hostPort"
]
=
fmt
.
Sprintf
(
"%s:%s"
,
host
,
port
)
delete
(
convertedObject
.
Object
,
"host"
)
delete
(
convertedObject
.
Object
,
"port"
)
}
default
:
return
nil
,
statusErrorWithMessage
(
"unexpected conversion version %q"
,
toVersion
)
}
default
:
return
nil
,
statusErrorWithMessage
(
"unexpected conversion version %q"
,
fromVersion
)
}
return
convertedObject
,
statusSucceed
()
}
test/images/crd-conversion-webhook/converter/framework.go
0 → 100644
View file @
97baad34
/*
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
converter
import
(
"bitbucket.org/ww/goautoneg"
"fmt"
"io/ioutil"
"net/http"
"strings"
"github.com/golang/glog"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
metav1
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer/json"
)
// convertFunc is the user defined function for any conversion. The code in this file is a
// template that can be use for any CR conversion given this function.
type
convertFunc
func
(
Object
*
unstructured
.
Unstructured
,
version
string
)
(
*
unstructured
.
Unstructured
,
metav1
.
Status
)
// conversionResponseFailureWithMessagef is a helper function to create an AdmissionResponse
// with a formatted embedded error message.
func
conversionResponseFailureWithMessagef
(
msg
string
,
params
...
interface
{})
*
v1beta1
.
ConversionResponse
{
return
&
v1beta1
.
ConversionResponse
{
Result
:
metav1
.
Status
{
Message
:
fmt
.
Sprintf
(
msg
,
params
...
),
Status
:
metav1
.
StatusFailure
,
},
}
}
func
statusErrorWithMessage
(
msg
string
,
params
...
interface
{})
metav1
.
Status
{
return
metav1
.
Status
{
Message
:
fmt
.
Sprintf
(
msg
,
params
...
),
Status
:
metav1
.
StatusFailure
,
}
}
func
statusSucceed
()
metav1
.
Status
{
return
metav1
.
Status
{
Status
:
metav1
.
StatusSuccess
,
}
}
// doConversion converts the requested object given the conversion function and returns a conversion response.
// failures will be reported as Reason in the conversion response.
func
doConversion
(
convertRequest
*
v1beta1
.
ConversionRequest
,
convert
convertFunc
)
*
v1beta1
.
ConversionResponse
{
var
convertedObjects
[]
runtime
.
RawExtension
for
_
,
obj
:=
range
convertRequest
.
Objects
{
cr
:=
unstructured
.
Unstructured
{}
if
err
:=
cr
.
UnmarshalJSON
(
obj
.
Raw
);
err
!=
nil
{
glog
.
Error
(
err
)
return
conversionResponseFailureWithMessagef
(
"failed to unmarshall object (%v) with error: %v"
,
string
(
obj
.
Raw
),
err
)
}
convertedCR
,
status
:=
convert
(
&
cr
,
convertRequest
.
DesiredAPIVersion
)
if
status
.
Status
!=
metav1
.
StatusSuccess
{
glog
.
Error
(
status
.
String
())
return
&
v1beta1
.
ConversionResponse
{
Result
:
status
,
}
}
convertedCR
.
SetAPIVersion
(
convertRequest
.
DesiredAPIVersion
)
convertedObjects
=
append
(
convertedObjects
,
runtime
.
RawExtension
{
Object
:
convertedCR
})
}
return
&
v1beta1
.
ConversionResponse
{
ConvertedObjects
:
convertedObjects
,
Result
:
statusSucceed
(),
}
}
func
serve
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
,
convert
convertFunc
)
{
var
body
[]
byte
if
r
.
Body
!=
nil
{
if
data
,
err
:=
ioutil
.
ReadAll
(
r
.
Body
);
err
==
nil
{
body
=
data
}
}
contentType
:=
r
.
Header
.
Get
(
"Content-Type"
)
serializer
:=
getInputSerializer
(
contentType
)
if
serializer
==
nil
{
msg
:=
fmt
.
Sprintf
(
"invalid Content-Type header `%s`"
,
contentType
)
glog
.
Errorf
(
msg
)
http
.
Error
(
w
,
msg
,
http
.
StatusBadRequest
)
return
}
glog
.
V
(
2
)
.
Infof
(
"handling request: %v"
,
body
)
convertReview
:=
v1beta1
.
ConversionReview
{}
if
_
,
_
,
err
:=
serializer
.
Decode
(
body
,
nil
,
&
convertReview
);
err
!=
nil
{
glog
.
Error
(
err
)
convertReview
.
Response
=
conversionResponseFailureWithMessagef
(
"failed to deserialize body (%v) with error %v"
,
string
(
body
),
err
)
}
else
{
convertReview
.
Response
=
doConversion
(
convertReview
.
Request
,
convert
)
convertReview
.
Response
.
UID
=
convertReview
.
Request
.
UID
}
glog
.
V
(
2
)
.
Info
(
fmt
.
Sprintf
(
"sending response: %v"
,
convertReview
.
Response
))
// reset the request, it is not needed in a response.
convertReview
.
Request
=
&
v1beta1
.
ConversionRequest
{}
accept
:=
r
.
Header
.
Get
(
"Accept"
)
outSerializer
:=
getOutputSerializer
(
accept
)
if
outSerializer
==
nil
{
msg
:=
fmt
.
Sprintf
(
"invalid accept header `%s`"
,
accept
)
glog
.
Errorf
(
msg
)
http
.
Error
(
w
,
msg
,
http
.
StatusBadRequest
)
return
}
err
:=
outSerializer
.
Encode
(
&
convertReview
,
w
)
if
err
!=
nil
{
glog
.
Error
(
err
)
http
.
Error
(
w
,
err
.
Error
(),
http
.
StatusInternalServerError
)
return
}
}
// ServeExampleConvert servers endpoint for the example converter defined as convertExampleCRD function.
func
ServeExampleConvert
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
serve
(
w
,
r
,
convertExampleCRD
)
}
type
mediaType
struct
{
Type
,
SubType
string
}
var
scheme
=
runtime
.
NewScheme
()
var
serializers
=
map
[
mediaType
]
runtime
.
Serializer
{
{
"application"
,
"json"
}
:
json
.
NewSerializer
(
json
.
DefaultMetaFactory
,
scheme
,
scheme
,
false
),
{
"application"
,
"yaml"
}
:
json
.
NewYAMLSerializer
(
json
.
DefaultMetaFactory
,
scheme
,
scheme
),
}
func
getInputSerializer
(
contentType
string
)
runtime
.
Serializer
{
parts
:=
strings
.
SplitN
(
contentType
,
"/"
,
2
)
if
len
(
parts
)
!=
2
{
return
nil
}
return
serializers
[
mediaType
{
parts
[
0
],
parts
[
1
]}]
}
func
getOutputSerializer
(
accept
string
)
runtime
.
Serializer
{
if
len
(
accept
)
==
0
{
return
serializers
[
mediaType
{
"application"
,
"json"
}]
}
clauses
:=
goautoneg
.
ParseAccept
(
accept
)
for
_
,
clause
:=
range
clauses
{
for
k
,
v
:=
range
serializers
{
switch
{
case
clause
.
Type
==
k
.
Type
&&
clause
.
SubType
==
k
.
SubType
,
clause
.
Type
==
k
.
Type
&&
clause
.
SubType
==
"*"
,
clause
.
Type
==
"*"
&&
clause
.
SubType
==
"*"
:
return
v
}
}
}
return
nil
}
test/images/crd-conversion-webhook/main.go
0 → 100644
View file @
97baad34
/*
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
main
import
(
"flag"
"net/http"
"k8s.io/kubernetes/test/images/crd-conversion-webhook/converter"
)
// Config contains the server (the webhook) cert and key.
type
Config
struct
{
CertFile
string
KeyFile
string
}
func
(
c
*
Config
)
addFlags
()
{
flag
.
StringVar
(
&
c
.
CertFile
,
"tls-cert-file"
,
c
.
CertFile
,
""
+
"File containing the default x509 Certificate for HTTPS. (CA cert, if any, concatenated "
+
"after server cert)."
)
flag
.
StringVar
(
&
c
.
KeyFile
,
"tls-private-key-file"
,
c
.
KeyFile
,
""
+
"File containing the default x509 private key matching --tls-cert-file."
)
}
func
main
()
{
var
config
Config
config
.
addFlags
()
flag
.
Parse
()
http
.
HandleFunc
(
"/crdconvert"
,
converter
.
ServeExampleConvert
)
clientset
:=
getClient
()
server
:=
&
http
.
Server
{
Addr
:
":443"
,
TLSConfig
:
configTLS
(
config
,
clientset
),
}
server
.
ListenAndServeTLS
(
""
,
""
)
}
test/utils/image/manifest.go
View file @
97baad34
...
@@ -92,6 +92,7 @@ var (
...
@@ -92,6 +92,7 @@ var (
// Preconfigured image configs
// Preconfigured image configs
var
(
var
(
CRDConversionWebhook
=
Config
{
e2eRegistry
,
"crd-conversion-webhook"
,
"1.13rev2"
}
AdmissionWebhook
=
Config
{
e2eRegistry
,
"webhook"
,
"1.13v1"
}
AdmissionWebhook
=
Config
{
e2eRegistry
,
"webhook"
,
"1.13v1"
}
APIServer
=
Config
{
e2eRegistry
,
"sample-apiserver"
,
"1.10"
}
APIServer
=
Config
{
e2eRegistry
,
"sample-apiserver"
,
"1.10"
}
AppArmorLoader
=
Config
{
e2eRegistry
,
"apparmor-loader"
,
"1.0"
}
AppArmorLoader
=
Config
{
e2eRegistry
,
"apparmor-loader"
,
"1.0"
}
...
...
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