Commit 3ee458d2 authored by deads2k's avatar deads2k

remove tpr API access

parent 17e19dfc
...@@ -41,7 +41,6 @@ import ( ...@@ -41,7 +41,6 @@ import (
apiregistrationclient "k8s.io/kube-aggregator/pkg/client/clientset_generated/internalclientset/typed/apiregistration/internalversion" apiregistrationclient "k8s.io/kube-aggregator/pkg/client/clientset_generated/internalclientset/typed/apiregistration/internalversion"
"k8s.io/kube-aggregator/pkg/controllers/autoregister" "k8s.io/kube-aggregator/pkg/controllers/autoregister"
"k8s.io/kubernetes/cmd/kube-apiserver/app/options" "k8s.io/kubernetes/cmd/kube-apiserver/app/options"
informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
"k8s.io/kubernetes/pkg/master/thirdparty" "k8s.io/kubernetes/pkg/master/thirdparty"
) )
...@@ -85,7 +84,7 @@ func createAggregatorConfig(kubeAPIServerConfig genericapiserver.Config, command ...@@ -85,7 +84,7 @@ func createAggregatorConfig(kubeAPIServerConfig genericapiserver.Config, command
return aggregatorConfig, nil return aggregatorConfig, nil
} }
func createAggregatorServer(aggregatorConfig *aggregatorapiserver.Config, delegateAPIServer genericapiserver.DelegationTarget, kubeInformers informers.SharedInformerFactory, apiExtensionInformers apiextensionsinformers.SharedInformerFactory) (*aggregatorapiserver.APIAggregator, error) { func createAggregatorServer(aggregatorConfig *aggregatorapiserver.Config, delegateAPIServer genericapiserver.DelegationTarget, apiExtensionInformers apiextensionsinformers.SharedInformerFactory) (*aggregatorapiserver.APIAggregator, error) {
aggregatorServer, err := aggregatorConfig.Complete().NewWithDelegate(delegateAPIServer) aggregatorServer, err := aggregatorConfig.Complete().NewWithDelegate(delegateAPIServer)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -98,14 +97,13 @@ func createAggregatorServer(aggregatorConfig *aggregatorapiserver.Config, delega ...@@ -98,14 +97,13 @@ func createAggregatorServer(aggregatorConfig *aggregatorapiserver.Config, delega
} }
autoRegistrationController := autoregister.NewAutoRegisterController(aggregatorServer.APIRegistrationInformers.Apiregistration().InternalVersion().APIServices(), apiRegistrationClient) autoRegistrationController := autoregister.NewAutoRegisterController(aggregatorServer.APIRegistrationInformers.Apiregistration().InternalVersion().APIServices(), apiRegistrationClient)
apiServices := apiServicesToRegister(delegateAPIServer, autoRegistrationController) apiServices := apiServicesToRegister(delegateAPIServer, autoRegistrationController)
tprRegistrationController := thirdparty.NewAutoRegistrationController( crdRegistrationController := thirdparty.NewAutoRegistrationController(
kubeInformers.Extensions().InternalVersion().ThirdPartyResources(),
apiExtensionInformers.Apiextensions().InternalVersion().CustomResourceDefinitions(), apiExtensionInformers.Apiextensions().InternalVersion().CustomResourceDefinitions(),
autoRegistrationController) autoRegistrationController)
aggregatorServer.GenericAPIServer.AddPostStartHook("kube-apiserver-autoregistration", func(context genericapiserver.PostStartHookContext) error { aggregatorServer.GenericAPIServer.AddPostStartHook("kube-apiserver-autoregistration", func(context genericapiserver.PostStartHookContext) error {
go autoRegistrationController.Run(5, context.StopCh) go autoRegistrationController.Run(5, context.StopCh)
go tprRegistrationController.Run(5, context.StopCh) go crdRegistrationController.Run(5, context.StopCh)
return nil return nil
}) })
aggregatorServer.GenericAPIServer.AddHealthzChecks(healthz.NamedCheck("autoregister-completion", func(r *http.Request) error { aggregatorServer.GenericAPIServer.AddHealthzChecks(healthz.NamedCheck("autoregister-completion", func(r *http.Request) error {
......
...@@ -161,7 +161,7 @@ func Run(runOptions *options.ServerRunOptions, stopCh <-chan struct{}) error { ...@@ -161,7 +161,7 @@ func Run(runOptions *options.ServerRunOptions, stopCh <-chan struct{}) error {
} }
aggregatorConfig.ProxyTransport = proxyTransport aggregatorConfig.ProxyTransport = proxyTransport
aggregatorConfig.ServiceResolver = serviceResolver aggregatorConfig.ServiceResolver = serviceResolver
aggregatorServer, err := createAggregatorServer(aggregatorConfig, kubeAPIServer.GenericAPIServer, sharedInformers, apiExtensionsServer.Informers) aggregatorServer, err := createAggregatorServer(aggregatorConfig, kubeAPIServer.GenericAPIServer, apiExtensionsServer.Informers)
if err != nil { if err != nil {
// we don't need special handling for innerStopCh because the aggregator server doesn't create any go routines // we don't need special handling for innerStopCh because the aggregator server doesn't create any go routines
return err return err
......
...@@ -382,12 +382,6 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; } ...@@ -382,12 +382,6 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
<p><a href="#_v1beta1_scale">v1beta1.Scale</a></p> <p><a href="#_v1beta1_scale">v1beta1.Scale</a></p>
</li> </li>
<li> <li>
<p><a href="#_v1beta1_thirdpartyresource">v1beta1.ThirdPartyResource</a></p>
</li>
<li>
<p><a href="#_v1beta1_thirdpartyresourcelist">v1beta1.ThirdPartyResourceList</a></p>
</li>
<li>
<p><a href="#_v1beta1_daemonsetlist">v1beta1.DaemonSetList</a></p> <p><a href="#_v1beta1_daemonsetlist">v1beta1.DaemonSetList</a></p>
</li> </li>
<li> <li>
...@@ -3254,40 +3248,6 @@ When an object is created, the system will populate this list with the current s ...@@ -3254,40 +3248,6 @@ When an object is created, the system will populate this list with the current s
</div> </div>
<div class="sect2"> <div class="sect2">
<h3 id="_v1beta1_apiversion">v1beta1.APIVersion</h3>
<div class="paragraph">
<p>An APIVersion represents a single concrete version of an object model.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Required</th>
<th class="tableblock halign-left valign-top">Schema</th>
<th class="tableblock halign-left valign-top">Default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">name</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Name of this version (e.g. <em>v1</em>).</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1beta1_supplementalgroupsstrategyoptions">v1beta1.SupplementalGroupsStrategyOptions</h3> <h3 id="_v1beta1_supplementalgroupsstrategyoptions">v1beta1.SupplementalGroupsStrategyOptions</h3>
<div class="paragraph"> <div class="paragraph">
<p>SupplementalGroupsStrategyOptions defines the strategy type and options used to create the strategy.</p> <p>SupplementalGroupsStrategyOptions defines the strategy type and options used to create the strategy.</p>
...@@ -5819,68 +5779,6 @@ Examples:<br> ...@@ -5819,68 +5779,6 @@ Examples:<br>
</div> </div>
<div class="sect2"> <div class="sect2">
<h3 id="_v1beta1_thirdpartyresource">v1beta1.ThirdPartyResource</h3>
<div class="paragraph">
<p>A ThirdPartyResource is a generic representation of a resource, it is used by add-ons and plugins to add new resource types to the API. It consists of one or more Versions of the api.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Required</th>
<th class="tableblock halign-left valign-top">Schema</th>
<th class="tableblock halign-left valign-top">Default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">kind</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: <a href="https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds">https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">apiVersion</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: <a href="https://git.k8s.io/community/contributors/devel/api-conventions.md#resources">https://git.k8s.io/community/contributors/devel/api-conventions.md#resources</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">metadata</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Standard object metadata</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_objectmeta">v1.ObjectMeta</a></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">description</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Description is the description of this object.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">versions</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Versions are versions for this third party object</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1beta1_apiversion">v1beta1.APIVersion</a> array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1_deletionpropagation">v1.DeletionPropagation</h3> <h3 id="_v1_deletionpropagation">v1.DeletionPropagation</h3>
</div> </div>
...@@ -8154,61 +8052,6 @@ Both these may change in the future. Incoming requests are matched against the h ...@@ -8154,61 +8052,6 @@ Both these may change in the future. Incoming requests are matched against the h
</div> </div>
<div class="sect2"> <div class="sect2">
<h3 id="_v1beta1_thirdpartyresourcelist">v1beta1.ThirdPartyResourceList</h3>
<div class="paragraph">
<p>ThirdPartyResourceList is a list of ThirdPartyResources.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Required</th>
<th class="tableblock halign-left valign-top">Schema</th>
<th class="tableblock halign-left valign-top">Default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">kind</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: <a href="https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds">https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">apiVersion</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: <a href="https://git.k8s.io/community/contributors/devel/api-conventions.md#resources">https://git.k8s.io/community/contributors/devel/api-conventions.md#resources</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">metadata</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Standard list metadata.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_listmeta">v1.ListMeta</a></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">items</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Items is the list of ThirdPartyResources.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1beta1_thirdpartyresource">v1beta1.ThirdPartyResource</a> array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1_azuredatadiskcachingmode">v1.AzureDataDiskCachingMode</h3> <h3 id="_v1_azuredatadiskcachingmode">v1.AzureDataDiskCachingMode</h3>
</div> </div>
......
...@@ -498,7 +498,6 @@ test/integration/quota ...@@ -498,7 +498,6 @@ test/integration/quota
test/integration/secrets test/integration/secrets
test/integration/serviceaccount test/integration/serviceaccount
test/integration/storageclasses test/integration/storageclasses
test/integration/thirdparty
test/integration/ttlcontroller test/integration/ttlcontroller
test/soak/cauldron test/soak/cauldron
test/soak/serve_hostnames test/soak/serve_hostnames
......
...@@ -1492,161 +1492,6 @@ __EOF__ ...@@ -1492,161 +1492,6 @@ __EOF__
set +o errexit set +o errexit
} }
run_tpr_tests() {
set -o nounset
set -o errexit
create_and_use_new_namespace
kube::log::status "Testing kubectl tpr"
kubectl "${kube_flags[@]}" create -f - "${kube_flags[@]}" << __EOF__
{
"kind": "ThirdPartyResource",
"apiVersion": "extensions/v1beta1",
"metadata": {
"name": "foo.company.com"
},
"versions": [
{
"name": "v1"
}
]
}
__EOF__
# Post-Condition: assertion object exist
kube::test::get_object_assert thirdpartyresources "{{range.items}}{{$id_field}}:{{end}}" 'foo.company.com:'
kubectl "${kube_flags[@]}" create -f - "${kube_flags[@]}" << __EOF__
{
"kind": "ThirdPartyResource",
"apiVersion": "extensions/v1beta1",
"metadata": {
"name": "bar.company.com"
},
"versions": [
{
"name": "v1"
}
]
}
__EOF__
# Post-Condition: assertion object exist
kube::test::get_object_assert thirdpartyresources "{{range.items}}{{$id_field}}:{{end}}" 'bar.company.com:foo.company.com:'
run_non_native_resource_tests
# teardown
kubectl delete thirdpartyresources/foo.company.com "${kube_flags[@]}"
kubectl delete thirdpartyresources/bar.company.com "${kube_flags[@]}"
set +o nounset
set +o errexit
}
run_tpr_migration_tests() {
set -o nounset
set -o errexit
kube::log::status "Testing kubectl tpr migration"
local i tries
create_and_use_new_namespace
# Create CRD first. This is sort of backwards so we can create a marker below.
kubectl "${kube_flags_with_token[@]}" create -f - << __EOF__
{
"kind": "CustomResourceDefinition",
"apiVersion": "apiextensions.k8s.io/v1beta1",
"metadata": {
"name": "foos.company.crd"
},
"spec": {
"group": "company.crd",
"version": "v1",
"names": {
"plural": "foos",
"kind": "Foo"
}
}
}
__EOF__
# Wait for API to become available.
tries=0
until kubectl "${kube_flags[@]}" get foos.company.crd || [ $tries -gt 10 ]; do
tries=$((tries+1))
sleep ${tries}
done
kube::test::get_object_assert foos.company.crd '{{len .items}}' '0'
# Create a marker that only exists in CRD so we know when CRD is active vs. TPR.
kubectl "${kube_flags[@]}" create -f - << __EOF__
{
"kind": "Foo",
"apiVersion": "company.crd/v1",
"metadata": {
"name": "crd-marker"
},
"testValue": "only exists in CRD"
}
__EOF__
kube::test::get_object_assert foos.company.crd '{{len .items}}' '1'
# Now create a TPR that sits in front of the CRD and hides it.
kubectl "${kube_flags[@]}" create -f - << __EOF__
{
"kind": "ThirdPartyResource",
"apiVersion": "extensions/v1beta1",
"metadata": {
"name": "foo.company.crd"
},
"versions": [
{
"name": "v1"
}
]
}
__EOF__
# The marker should disappear.
kube::test::wait_object_assert foos.company.crd '{{len .items}}' '0'
# Add some items to the TPR.
for i in {1..10}; do
kubectl "${kube_flags[@]}" create -f - << __EOF__
{
"kind": "Foo",
"apiVersion": "company.crd/v1",
"metadata": {
"name": "tpr-${i}"
},
"testValue": "migrate-${i}"
}
__EOF__
done
kube::test::get_object_assert foos.company.crd '{{len .items}}' '10'
# Delete the TPR and wait for the CRD to take over.
kubectl "${kube_flags[@]}" delete thirdpartyresource/foo.company.crd
tries=0
until kubectl "${kube_flags[@]}" get foos.company.crd/crd-marker || [ $tries -gt 10 ]; do
tries=$((tries+1))
sleep ${tries}
done
kube::test::get_object_assert foos.company.crd/crd-marker '{{.testValue}}' 'only exists in CRD'
# Check if the TPR items were migrated to CRD.
kube::test::get_object_assert foos.company.crd '{{len .items}}' '11'
for i in {1..10}; do
kube::test::get_object_assert foos.company.crd/tpr-${i} '{{.testValue}}' "migrate-${i}"
done
# teardown
kubectl delete customresourcedefinitions/foos.company.crd "${kube_flags_with_token[@]}"
set +o nounset
set +o errexit
}
kube::util::non_native_resources() { kube::util::non_native_resources() {
local times local times
local wait local wait
...@@ -4455,13 +4300,6 @@ runTests() { ...@@ -4455,13 +4300,6 @@ runTests() {
record_command run_crd_tests record_command run_crd_tests
fi fi
if kube::test::if_supports_resource "${thirdpartyresources}" ; then
record_command run_tpr_tests
if kube::test::if_supports_resource "${customresourcedefinitions}" ; then
record_command run_tpr_migration_tests
fi
fi
################# #################
# Run cmd w img # # Run cmd w img #
################# #################
......
...@@ -18,8 +18,6 @@ go_library( ...@@ -18,8 +18,6 @@ go_library(
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/apis/extensions:go_default_library", "//pkg/apis/extensions:go_default_library",
"//pkg/client/informers/informers_generated/internalversion/extensions/internalversion:go_default_library",
"//pkg/client/listers/extensions/internalversion:go_default_library",
"//pkg/controller:go_default_library", "//pkg/controller:go_default_library",
"//pkg/registry/extensions/rest:go_default_library", "//pkg/registry/extensions/rest:go_default_library",
"//pkg/registry/extensions/thirdpartyresourcedata:go_default_library", "//pkg/registry/extensions/thirdpartyresourcedata:go_default_library",
...@@ -75,14 +73,11 @@ go_test( ...@@ -75,14 +73,11 @@ go_test(
library = ":go_default_library", library = ":go_default_library",
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//pkg/apis/extensions:go_default_library",
"//pkg/client/listers/extensions/internalversion:go_default_library",
"//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library", "//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library",
"//vendor/k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/internalversion:go_default_library", "//vendor/k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/internalversion:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/client-go/tools/cache:go_default_library", "//vendor/k8s.io/client-go/tools/cache:go_default_library",
"//vendor/k8s.io/client-go/util/workqueue:go_default_library",
"//vendor/k8s.io/kube-aggregator/pkg/apis/apiregistration:go_default_library", "//vendor/k8s.io/kube-aggregator/pkg/apis/apiregistration:go_default_library",
], ],
) )
...@@ -33,11 +33,7 @@ import ( ...@@ -33,11 +33,7 @@ import (
"k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue" "k8s.io/client-go/util/workqueue"
"k8s.io/kube-aggregator/pkg/apis/apiregistration" "k8s.io/kube-aggregator/pkg/apis/apiregistration"
"k8s.io/kubernetes/pkg/apis/extensions"
informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion/extensions/internalversion"
listers "k8s.io/kubernetes/pkg/client/listers/extensions/internalversion"
"k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/controller"
"k8s.io/kubernetes/pkg/registry/extensions/thirdpartyresourcedata"
) )
// AutoAPIServiceRegistration is an interface which callers can re-declare locally and properly cast to for // AutoAPIServiceRegistration is an interface which callers can re-declare locally and properly cast to for
...@@ -49,9 +45,7 @@ type AutoAPIServiceRegistration interface { ...@@ -49,9 +45,7 @@ type AutoAPIServiceRegistration interface {
RemoveAPIServiceToSync(name string) RemoveAPIServiceToSync(name string)
} }
type tprRegistrationController struct { type crdRegistrationController struct {
tprLister listers.ThirdPartyResourceLister
tprSynced cache.InformerSynced
crdLister crdlisters.CustomResourceDefinitionLister crdLister crdlisters.CustomResourceDefinitionLister
crdSynced cache.InformerSynced crdSynced cache.InformerSynced
...@@ -68,44 +62,15 @@ type tprRegistrationController struct { ...@@ -68,44 +62,15 @@ type tprRegistrationController struct {
// controller so they automatically stay in sync. // controller so they automatically stay in sync.
// In order to stay sane with both TPR and CRD present, we have a single controller that manages both. When choosing whether to have an // In order to stay sane with both TPR and CRD present, we have a single controller that manages both. When choosing whether to have an
// APIService, we simply iterate through both. // APIService, we simply iterate through both.
func NewAutoRegistrationController(tprInformer informers.ThirdPartyResourceInformer, crdinformer crdinformers.CustomResourceDefinitionInformer, apiServiceRegistration AutoAPIServiceRegistration) *tprRegistrationController { func NewAutoRegistrationController(crdinformer crdinformers.CustomResourceDefinitionInformer, apiServiceRegistration AutoAPIServiceRegistration) *crdRegistrationController {
c := &tprRegistrationController{ c := &crdRegistrationController{
tprLister: tprInformer.Lister(),
tprSynced: tprInformer.Informer().HasSynced,
crdLister: crdinformer.Lister(), crdLister: crdinformer.Lister(),
crdSynced: crdinformer.Informer().HasSynced, crdSynced: crdinformer.Informer().HasSynced,
apiServiceRegistration: apiServiceRegistration, apiServiceRegistration: apiServiceRegistration,
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "tpr-autoregister"), queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "crd-autoregister"),
} }
c.syncHandler = c.handleVersionUpdate c.syncHandler = c.handleVersionUpdate
tprInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
cast := obj.(*extensions.ThirdPartyResource)
c.enqueueTPR(cast)
},
UpdateFunc: func(_, obj interface{}) {
cast := obj.(*extensions.ThirdPartyResource)
c.enqueueTPR(cast)
},
DeleteFunc: func(obj interface{}) {
cast, ok := obj.(*extensions.ThirdPartyResource)
if !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok {
glog.V(2).Infof("Couldn't get object from tombstone %#v", obj)
return
}
cast, ok = tombstone.Obj.(*extensions.ThirdPartyResource)
if !ok {
glog.V(2).Infof("Tombstone contained unexpected object: %#v", obj)
return
}
}
c.enqueueTPR(cast)
},
})
crdinformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ crdinformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) { AddFunc: func(obj interface{}) {
cast := obj.(*apiextensions.CustomResourceDefinition) cast := obj.(*apiextensions.CustomResourceDefinition)
...@@ -136,16 +101,16 @@ func NewAutoRegistrationController(tprInformer informers.ThirdPartyResourceInfor ...@@ -136,16 +101,16 @@ func NewAutoRegistrationController(tprInformer informers.ThirdPartyResourceInfor
return c return c
} }
func (c *tprRegistrationController) Run(threadiness int, stopCh <-chan struct{}) { func (c *crdRegistrationController) Run(threadiness int, stopCh <-chan struct{}) {
defer utilruntime.HandleCrash() defer utilruntime.HandleCrash()
// make sure the work queue is shutdown which will trigger workers to end // make sure the work queue is shutdown which will trigger workers to end
defer c.queue.ShutDown() defer c.queue.ShutDown()
glog.Infof("Starting tpr-autoregister controller") glog.Infof("Starting crd-autoregister controller")
defer glog.Infof("Shutting down tpr-autoregister controller") defer glog.Infof("Shutting down crd-autoregister controller")
// wait for your secondary caches to fill before starting your work // wait for your secondary caches to fill before starting your work
if !controller.WaitForCacheSync("tpr-autoregister", stopCh, c.tprSynced) { if !controller.WaitForCacheSync("crd-autoregister", stopCh, c.crdSynced) {
return return
} }
...@@ -160,7 +125,7 @@ func (c *tprRegistrationController) Run(threadiness int, stopCh <-chan struct{}) ...@@ -160,7 +125,7 @@ func (c *tprRegistrationController) Run(threadiness int, stopCh <-chan struct{})
<-stopCh <-stopCh
} }
func (c *tprRegistrationController) runWorker() { func (c *crdRegistrationController) runWorker() {
// hot loop until we're told to stop. processNextWorkItem will automatically wait until there's work // hot loop until we're told to stop. processNextWorkItem will automatically wait until there's work
// available, so we don't worry about secondary waits // available, so we don't worry about secondary waits
for c.processNextWorkItem() { for c.processNextWorkItem() {
...@@ -168,7 +133,7 @@ func (c *tprRegistrationController) runWorker() { ...@@ -168,7 +133,7 @@ func (c *tprRegistrationController) runWorker() {
} }
// processNextWorkItem deals with one key off the queue. It returns false when it's time to quit. // processNextWorkItem deals with one key off the queue. It returns false when it's time to quit.
func (c *tprRegistrationController) processNextWorkItem() bool { func (c *crdRegistrationController) processNextWorkItem() bool {
// pull the next work item from queue. It should be a key we use to lookup something in a cache // pull the next work item from queue. It should be a key we use to lookup something in a cache
key, quit := c.queue.Get() key, quit := c.queue.Get()
if quit { if quit {
...@@ -198,43 +163,14 @@ func (c *tprRegistrationController) processNextWorkItem() bool { ...@@ -198,43 +163,14 @@ func (c *tprRegistrationController) processNextWorkItem() bool {
return true return true
} }
func (c *tprRegistrationController) enqueueTPR(tpr *extensions.ThirdPartyResource) { func (c *crdRegistrationController) enqueueCRD(crd *apiextensions.CustomResourceDefinition) {
_, group, err := thirdpartyresourcedata.ExtractApiGroupAndKind(tpr)
if err != nil {
utilruntime.HandleError(err)
return
}
for _, version := range tpr.Versions {
c.queue.Add(schema.GroupVersion{Group: group, Version: version.Name})
}
}
func (c *tprRegistrationController) enqueueCRD(crd *apiextensions.CustomResourceDefinition) {
c.queue.Add(schema.GroupVersion{Group: crd.Spec.Group, Version: crd.Spec.Version}) c.queue.Add(schema.GroupVersion{Group: crd.Spec.Group, Version: crd.Spec.Version})
} }
func (c *tprRegistrationController) handleVersionUpdate(groupVersion schema.GroupVersion) error { func (c *crdRegistrationController) handleVersionUpdate(groupVersion schema.GroupVersion) error {
found := false found := false
apiServiceName := groupVersion.Version + "." + groupVersion.Group apiServiceName := groupVersion.Version + "." + groupVersion.Group
// check all TPRs. There shouldn't that many, but if we have problems later we can index them
tprs, err := c.tprLister.List(labels.Everything())
if err != nil {
return err
}
for _, tpr := range tprs {
_, group, err := thirdpartyresourcedata.ExtractApiGroupAndKind(tpr)
if err != nil {
return err
}
for _, version := range tpr.Versions {
if version.Name == groupVersion.Version && group == groupVersion.Group {
found = true
break
}
}
}
// check all CRDs. There shouldn't that many, but if we have problems later we can index them // check all CRDs. There shouldn't that many, but if we have problems later we can index them
crds, err := c.crdLister.List(labels.Everything()) crds, err := c.crdLister.List(labels.Everything())
if err != nil { if err != nil {
......
...@@ -25,43 +25,12 @@ import ( ...@@ -25,43 +25,12 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
"k8s.io/kube-aggregator/pkg/apis/apiregistration" "k8s.io/kube-aggregator/pkg/apis/apiregistration"
"k8s.io/kubernetes/pkg/apis/extensions"
listers "k8s.io/kubernetes/pkg/client/listers/extensions/internalversion"
) )
func TestEnqueue(t *testing.T) {
c := tprRegistrationController{
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "tpr-autoregister"),
}
tpr := &extensions.ThirdPartyResource{
ObjectMeta: metav1.ObjectMeta{Name: "resource.group.example.com"},
Versions: []extensions.APIVersion{
{Name: "v1alpha1"},
{Name: "v1"},
},
}
c.enqueueTPR(tpr)
first, _ := c.queue.Get()
expectedFirst := schema.GroupVersion{Group: "group.example.com", Version: "v1alpha1"}
if first != expectedFirst {
t.Errorf("expected %v, got %v", expectedFirst, first)
}
second, _ := c.queue.Get()
expectedSecond := schema.GroupVersion{Group: "group.example.com", Version: "v1"}
if second != expectedSecond {
t.Errorf("expected %v, got %v", expectedSecond, second)
}
}
func TestHandleVersionUpdate(t *testing.T) { func TestHandleVersionUpdate(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
startingTPRs []*extensions.ThirdPartyResource
startingCRDs []*apiextensions.CustomResourceDefinition startingCRDs []*apiextensions.CustomResourceDefinition
version schema.GroupVersion version schema.GroupVersion
...@@ -69,44 +38,6 @@ func TestHandleVersionUpdate(t *testing.T) { ...@@ -69,44 +38,6 @@ func TestHandleVersionUpdate(t *testing.T) {
expectedRemoved []string expectedRemoved []string
}{ }{
{ {
name: "simple add tpr",
startingTPRs: []*extensions.ThirdPartyResource{
{
ObjectMeta: metav1.ObjectMeta{Name: "resource.group.com"},
Versions: []extensions.APIVersion{
{Name: "v1"},
},
},
},
version: schema.GroupVersion{Group: "group.com", Version: "v1"},
expectedAdded: []*apiregistration.APIService{
{
ObjectMeta: metav1.ObjectMeta{Name: "v1.group.com"},
Spec: apiregistration.APIServiceSpec{
Group: "group.com",
Version: "v1",
GroupPriorityMinimum: 1000,
VersionPriority: 100,
},
},
},
},
{
name: "simple remove tpr",
startingTPRs: []*extensions.ThirdPartyResource{
{
ObjectMeta: metav1.ObjectMeta{Name: "resource.group.com"},
Versions: []extensions.APIVersion{
{Name: "v1"},
},
},
},
version: schema.GroupVersion{Group: "group.com", Version: "v2"},
expectedRemoved: []string{"v2.group.com"},
},
{
name: "simple add crd", name: "simple add crd",
startingCRDs: []*apiextensions.CustomResourceDefinition{ startingCRDs: []*apiextensions.CustomResourceDefinition{
{ {
...@@ -148,18 +79,12 @@ func TestHandleVersionUpdate(t *testing.T) { ...@@ -148,18 +79,12 @@ func TestHandleVersionUpdate(t *testing.T) {
for _, test := range tests { for _, test := range tests {
registration := &fakeAPIServiceRegistration{} registration := &fakeAPIServiceRegistration{}
tprCache := cache.NewIndexer(cache.DeletionHandlingMetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
tprLister := listers.NewThirdPartyResourceLister(tprCache)
crdCache := cache.NewIndexer(cache.DeletionHandlingMetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) crdCache := cache.NewIndexer(cache.DeletionHandlingMetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
crdLister := crdlisters.NewCustomResourceDefinitionLister(crdCache) crdLister := crdlisters.NewCustomResourceDefinitionLister(crdCache)
c := tprRegistrationController{ c := crdRegistrationController{
tprLister: tprLister,
crdLister: crdLister, crdLister: crdLister,
apiServiceRegistration: registration, apiServiceRegistration: registration,
} }
for i := range test.startingTPRs {
tprCache.Add(test.startingTPRs[i])
}
for i := range test.startingCRDs { for i := range test.startingCRDs {
crdCache.Add(test.startingCRDs[i]) crdCache.Add(test.startingCRDs[i])
} }
......
...@@ -39,15 +39,11 @@ go_library( ...@@ -39,15 +39,11 @@ go_library(
"//pkg/registry/extensions/networkpolicy/storage:go_default_library", "//pkg/registry/extensions/networkpolicy/storage:go_default_library",
"//pkg/registry/extensions/podsecuritypolicy/storage:go_default_library", "//pkg/registry/extensions/podsecuritypolicy/storage:go_default_library",
"//pkg/registry/extensions/replicaset/storage:go_default_library", "//pkg/registry/extensions/replicaset/storage:go_default_library",
"//pkg/registry/extensions/thirdpartyresource/storage:go_default_library",
"//pkg/registry/extensions/thirdpartyresourcedata:go_default_library", "//pkg/registry/extensions/thirdpartyresourcedata:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library", "//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/generic:go_default_library", "//vendor/k8s.io/apiserver/pkg/registry/generic:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library", "//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library",
"//vendor/k8s.io/apiserver/pkg/server:go_default_library", "//vendor/k8s.io/apiserver/pkg/server:go_default_library",
......
...@@ -17,21 +17,13 @@ limitations under the License. ...@@ -17,21 +17,13 @@ limitations under the License.
package rest package rest
import ( import (
"fmt"
"time"
"github.com/golang/glog"
extensionsapiv1beta1 "k8s.io/api/extensions/v1beta1" extensionsapiv1beta1 "k8s.io/api/extensions/v1beta1"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/generic"
"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/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
extensionsclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/extensions/internalversion"
expcontrollerstore "k8s.io/kubernetes/pkg/registry/extensions/controller/storage" expcontrollerstore "k8s.io/kubernetes/pkg/registry/extensions/controller/storage"
daemonstore "k8s.io/kubernetes/pkg/registry/extensions/daemonset/storage" daemonstore "k8s.io/kubernetes/pkg/registry/extensions/daemonset/storage"
deploymentstore "k8s.io/kubernetes/pkg/registry/extensions/deployment/storage" deploymentstore "k8s.io/kubernetes/pkg/registry/extensions/deployment/storage"
...@@ -39,7 +31,6 @@ import ( ...@@ -39,7 +31,6 @@ import (
networkpolicystore "k8s.io/kubernetes/pkg/registry/extensions/networkpolicy/storage" networkpolicystore "k8s.io/kubernetes/pkg/registry/extensions/networkpolicy/storage"
pspstore "k8s.io/kubernetes/pkg/registry/extensions/podsecuritypolicy/storage" pspstore "k8s.io/kubernetes/pkg/registry/extensions/podsecuritypolicy/storage"
replicasetstore "k8s.io/kubernetes/pkg/registry/extensions/replicaset/storage" replicasetstore "k8s.io/kubernetes/pkg/registry/extensions/replicaset/storage"
thirdpartyresourcestore "k8s.io/kubernetes/pkg/registry/extensions/thirdpartyresource/storage"
) )
type RESTStorageProvider struct { type RESTStorageProvider struct {
...@@ -70,11 +61,6 @@ func (p RESTStorageProvider) v1beta1Storage(apiResourceConfigSource serverstorag ...@@ -70,11 +61,6 @@ func (p RESTStorageProvider) v1beta1Storage(apiResourceConfigSource serverstorag
storage["replicationcontrollers"] = controllerStorage.ReplicationController storage["replicationcontrollers"] = controllerStorage.ReplicationController
storage["replicationcontrollers/scale"] = controllerStorage.Scale storage["replicationcontrollers/scale"] = controllerStorage.Scale
if apiResourceConfigSource.ResourceEnabled(version.WithResource("thirdpartyresources")) {
thirdPartyResourceStorage := thirdpartyresourcestore.NewREST(restOptionsGetter)
storage["thirdpartyresources"] = thirdPartyResourceStorage
}
if apiResourceConfigSource.ResourceEnabled(version.WithResource("daemonsets")) { if apiResourceConfigSource.ResourceEnabled(version.WithResource("daemonsets")) {
daemonSetStorage, daemonSetStatusStorage := daemonstore.NewREST(restOptionsGetter) daemonSetStorage, daemonSetStatusStorage := daemonstore.NewREST(restOptionsGetter)
storage["daemonsets"] = daemonSetStorage storage["daemonsets"] = daemonSetStorage
...@@ -110,29 +96,6 @@ func (p RESTStorageProvider) v1beta1Storage(apiResourceConfigSource serverstorag ...@@ -110,29 +96,6 @@ func (p RESTStorageProvider) v1beta1Storage(apiResourceConfigSource serverstorag
return storage return storage
} }
func (p RESTStorageProvider) PostStartHook() (string, genericapiserver.PostStartHookFunc, error) {
return "extensions/third-party-resources", p.postStartHookFunc, nil
}
func (p RESTStorageProvider) postStartHookFunc(hookContext genericapiserver.PostStartHookContext) error {
clientset, err := extensionsclient.NewForConfig(hookContext.LoopbackClientConfig)
if err != nil {
utilruntime.HandleError(fmt.Errorf("unable to initialize client: %v", err))
return nil
}
thirdPartyControl := ThirdPartyController{
master: p.ResourceInterface,
client: clientset,
}
go wait.Forever(func() {
if err := thirdPartyControl.SyncResources(); err != nil {
glog.Warningf("third party resource sync failed: %v", err)
}
}, 10*time.Second)
return nil
}
func (p RESTStorageProvider) GroupName() string { func (p RESTStorageProvider) GroupName() string {
return extensions.GroupName return extensions.GroupName
} }
...@@ -104,7 +104,6 @@ go_library( ...@@ -104,7 +104,6 @@ go_library(
"serviceloadbalancers.go", "serviceloadbalancers.go",
"ssh.go", "ssh.go",
"stackdriver_monitoring.go", "stackdriver_monitoring.go",
"third-party.go",
"ubernetes_lite.go", "ubernetes_lite.go",
"util_iperf.go", "util_iperf.go",
], ],
......
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package e2e
import (
"encoding/json"
"fmt"
"net/http"
"time"
extensions "k8s.io/api/extensions/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/test/e2e/framework"
. "github.com/onsi/ginkgo"
)
var data = `{
"kind": "Foo",
"apiVersion": "company.com/v1",
"metadata": {
"name": "bazz"
},
"someField": "hello world",
"otherField": 1
}`
type Foo struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty" description:"standard object metadata"`
SomeField string `json:"someField"`
OtherField int `json:"otherField"`
}
type FooList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty" description:"standard list metadata; see https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata"`
Items []Foo `json:"items"`
}
// This test is marked flaky pending namespace controller observing dynamic creation of new third party types.
var _ = Describe("ThirdParty resources [Flaky] [Disruptive]", func() {
f := framework.NewDefaultFramework("thirdparty")
rsrc := &extensions.ThirdPartyResource{
ObjectMeta: metav1.ObjectMeta{
Name: "foo.company.com",
},
Versions: []extensions.APIVersion{
{Name: "v1"},
},
}
Context("Simple Third Party", func() {
It("creating/deleting thirdparty objects works [Conformance]", func() {
defer func() {
if err := f.ClientSet.Extensions().ThirdPartyResources().Delete(rsrc.Name, nil); err != nil {
framework.Failf("failed to delete third party resource: %v", err)
}
}()
if _, err := f.ClientSet.Extensions().ThirdPartyResources().Create(rsrc); err != nil {
framework.Failf("failed to create third party resource: %v", err)
}
wait.Poll(time.Second*30, time.Minute*5, func() (bool, error) {
data, err := f.ClientSet.Extensions().RESTClient().Get().AbsPath("/apis/company.com/v1/foos").DoRaw()
if err != nil {
return false, err
}
meta := metav1.TypeMeta{}
if err := json.Unmarshal(data, &meta); err != nil {
return false, err
}
if meta.Kind == "FooList" {
return true, nil
}
status := metav1.Status{}
if err := runtime.DecodeInto(api.Codecs.LegacyCodec(api.Registry.EnabledVersions()...), data, &status); err != nil {
return false, err
}
if status.Code != http.StatusNotFound {
return false, fmt.Errorf("Unexpected status: %v", status)
}
return false, nil
})
data, err := f.ClientSet.Extensions().RESTClient().Get().AbsPath("/apis/company.com/v1/foos").DoRaw()
if err != nil {
framework.Failf("failed to list with no objects: %v", err)
}
list := FooList{}
if err := json.Unmarshal(data, &list); err != nil {
framework.Failf("failed to decode: %#v", err)
}
if len(list.Items) != 0 {
framework.Failf("unexpected object before create: %v", list)
}
foo := &Foo{
TypeMeta: metav1.TypeMeta{
Kind: "Foo",
},
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
SomeField: "bar",
OtherField: 10,
}
bodyData, err := json.Marshal(foo)
if err != nil {
framework.Failf("failed to marshal: %v", err)
}
if _, err := f.ClientSet.Extensions().RESTClient().Post().AbsPath("/apis/company.com/v1/namespaces/default/foos").Body(bodyData).DoRaw(); err != nil {
framework.Failf("failed to create: %v", err)
}
data, err = f.ClientSet.Extensions().RESTClient().Get().AbsPath("/apis/company.com/v1/namespaces/default/foos/foo").DoRaw()
if err != nil {
framework.Failf("failed to get object: %v", err)
}
out := Foo{}
if err := json.Unmarshal(data, &out); err != nil {
framework.Failf("failed to decode: %#v", err)
}
if out.Name != foo.Name || out.SomeField != foo.SomeField || out.OtherField != foo.OtherField {
framework.Failf("expected:\n%#v\nsaw:\n%#v\n%s\n", foo, &out, string(data))
}
data, err = f.ClientSet.Extensions().RESTClient().Get().AbsPath("/apis/company.com/v1/foos").DoRaw()
if err != nil {
framework.Failf("failed to list with no objects: %v", err)
}
if err := json.Unmarshal(data, &list); err != nil {
framework.Failf("failed to decode: %#v", err)
}
if len(list.Items) != 1 {
framework.Failf("unexpected object too few or too many: %v", list)
}
if list.Items[0].Name != foo.Name || list.Items[0].SomeField != foo.SomeField || list.Items[0].OtherField != foo.OtherField {
framework.Failf("expected: %#v, saw in list: %#v", foo, list.Items[0])
}
// Need to manually do the serialization because otherwise the
// Content-Type header is set to protobuf, the thirdparty codec in
// the API server side only accepts JSON.
deleteOptionsData, err := json.Marshal(metav1.NewDeleteOptions(10))
framework.ExpectNoError(err)
if _, err := f.ClientSet.Core().RESTClient().Delete().
AbsPath("/apis/company.com/v1/namespaces/default/foos/foo").
Body(deleteOptionsData).
DoRaw(); err != nil {
framework.Failf("failed to delete: %v", err)
}
data, err = f.ClientSet.Extensions().RESTClient().Get().AbsPath("/apis/company.com/v1/foos").DoRaw()
if err != nil {
framework.Failf("failed to list with no objects: %v", err)
}
if err := json.Unmarshal(data, &list); err != nil {
framework.Failf("failed to decode: %#v", err)
}
if len(list.Items) != 0 {
framework.Failf("unexpected object after delete: %v", list)
}
})
})
})
...@@ -60,7 +60,6 @@ filegroup( ...@@ -60,7 +60,6 @@ filegroup(
"//test/integration/secrets:all-srcs", "//test/integration/secrets:all-srcs",
"//test/integration/serviceaccount:all-srcs", "//test/integration/serviceaccount:all-srcs",
"//test/integration/storageclasses:all-srcs", "//test/integration/storageclasses:all-srcs",
"//test/integration/thirdparty:all-srcs",
"//test/integration/ttlcontroller:all-srcs", "//test/integration/ttlcontroller:all-srcs",
"//test/integration/volume:all-srcs", "//test/integration/volume:all-srcs",
], ],
......
...@@ -197,10 +197,6 @@ var etcdStorageData = map[schema.GroupVersionResource]struct { ...@@ -197,10 +197,6 @@ var etcdStorageData = map[schema.GroupVersionResource]struct {
stub: `{"metadata": {"name": "psp1"}, "spec": {"fsGroup": {"rule": "RunAsAny"}, "privileged": true, "runAsUser": {"rule": "RunAsAny"}, "seLinux": {"rule": "MustRunAs"}, "supplementalGroups": {"rule": "RunAsAny"}}}`, stub: `{"metadata": {"name": "psp1"}, "spec": {"fsGroup": {"rule": "RunAsAny"}, "privileged": true, "runAsUser": {"rule": "RunAsAny"}, "seLinux": {"rule": "MustRunAs"}, "supplementalGroups": {"rule": "RunAsAny"}}}`,
expectedEtcdPath: "/registry/podsecuritypolicy/psp1", expectedEtcdPath: "/registry/podsecuritypolicy/psp1",
}, },
gvr("extensions", "v1beta1", "thirdpartyresources"): {
stub: `{"description": "third party", "metadata": {"name": "kind.domain.tld"}, "versions": [{"name": "v3"}]}`,
expectedEtcdPath: "/registry/thirdpartyresources/kind.domain.tld",
},
gvr("extensions", "v1beta1", "ingresses"): { gvr("extensions", "v1beta1", "ingresses"): {
stub: `{"metadata": {"name": "ingress1"}, "spec": {"backend": {"serviceName": "service", "servicePort": 5000}}}`, stub: `{"metadata": {"name": "ingress1"}, "spec": {"backend": {"serviceName": "service", "servicePort": 5000}}}`,
expectedEtcdPath: "/registry/ingress/etcdstoragepathtestnamespace/ingress1", expectedEtcdPath: "/registry/ingress/etcdstoragepathtestnamespace/ingress1",
...@@ -372,6 +368,7 @@ var ephemeralWhiteList = createEphemeralWhiteList( ...@@ -372,6 +368,7 @@ var ephemeralWhiteList = createEphemeralWhiteList(
gvr("extensions", "v1beta1", "replicationcontrollerdummies"), // not stored in etcd gvr("extensions", "v1beta1", "replicationcontrollerdummies"), // not stored in etcd
gvr("extensions", "v1beta1", "scales"), // not stored in etcd, part of kapiv1.ReplicationController gvr("extensions", "v1beta1", "scales"), // not stored in etcd, part of kapiv1.ReplicationController
gvr("extensions", "v1beta1", "thirdpartyresourcedatas"), // we cannot create this gvr("extensions", "v1beta1", "thirdpartyresourcedatas"), // we cannot create this
gvr("extensions", "v1beta1", "thirdpartyresources"), // these have been removed from the API server, but kept for the client
// -- // --
// k8s.io/kubernetes/pkg/apis/imagepolicy/v1alpha1 // k8s.io/kubernetes/pkg/apis/imagepolicy/v1alpha1
......
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
)
go_test(
name = "go_default_test",
srcs = [
"client-go_test.go",
"thirdparty_test.go",
],
tags = [
"automanaged",
"integration",
],
deps = [
"//pkg/api:go_default_library",
"//pkg/client/clientset_generated/clientset:go_default_library",
"//test/integration/framework:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//vendor/k8s.io/client-go/examples/third-party-resources-deprecated/apis/tpr/v1:go_default_library",
"//vendor/k8s.io/client-go/examples/third-party-resources-deprecated/client:go_default_library",
"//vendor/k8s.io/client-go/examples/third-party-resources-deprecated/controller:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)
/*
Copyright 2017 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 thirdparty
import (
"context"
"testing"
apiv1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/kubernetes/test/integration/framework"
exampletprv1 "k8s.io/client-go/examples/third-party-resources-deprecated/apis/tpr/v1"
exampleclient "k8s.io/client-go/examples/third-party-resources-deprecated/client"
examplecontroller "k8s.io/client-go/examples/third-party-resources-deprecated/controller"
)
func TestClientGoThirdPartyResourceExample(t *testing.T) {
_, s, closeFn := framework.RunAMaster(framework.NewIntegrationTestMasterConfig())
defer closeFn()
scheme := runtime.NewScheme()
if err := exampletprv1.AddToScheme(scheme); err != nil {
t.Fatalf("unexpected error: %v", err)
}
config := &rest.Config{Host: s.URL, ContentConfig: rest.ContentConfig{
NegotiatedSerializer: serializer.DirectCodecFactory{CodecFactory: serializer.NewCodecFactory(scheme)},
}}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
t.Logf("Creating TPR %q", exampletprv1.ExampleResourcePlural)
if err := exampleclient.CreateTPR(clientset); err != nil {
t.Fatalf("unexpected error creating the ThirdPartyResource: %v", err)
}
exampleClient, exampleScheme, err := exampleclient.NewClient(config)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
t.Logf("Waiting for TPR %q to show up", exampletprv1.ExampleResourcePlural)
if err := exampleclient.WaitForExampleResource(exampleClient); err != nil {
t.Fatalf("TPR examples did not show up: %v", err)
}
t.Logf("TPR %q is active", exampletprv1.ExampleResourcePlural)
t.Logf("Starting a controller on instances of TPR %q", exampletprv1.ExampleResourcePlural)
controller := examplecontroller.ExampleController{
ExampleClient: exampleClient,
ExampleScheme: exampleScheme,
}
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
go controller.Run(ctx)
// Create an instance of our TPR
t.Logf("Creating instance of TPR %q", exampletprv1.ExampleResourcePlural)
example := &exampletprv1.Example{
ObjectMeta: metav1.ObjectMeta{
Name: "example1",
},
Spec: exampletprv1.ExampleSpec{
Foo: "hello",
Bar: true,
},
Status: exampletprv1.ExampleStatus{
State: exampletprv1.ExampleStateCreated,
Message: "Created, not processed yet",
},
}
var result exampletprv1.Example
err = exampleClient.Post().
Resource(exampletprv1.ExampleResourcePlural).
Namespace(apiv1.NamespaceDefault).
Body(example).
Do().Into(&result)
if err != nil {
t.Fatalf("Failed to create an instance of TPR: %v", err)
}
t.Logf("Waiting for TPR %q instance to be processed", exampletprv1.ExampleResourcePlural)
if err := exampleclient.WaitForExampleInstanceProcessed(exampleClient, "example1"); err != nil {
t.Fatalf("TPR example was not processed correctly: %v", err)
}
t.Logf("TPR %q instance is processed", exampletprv1.ExampleResourcePlural)
}
/*
Copyright 2015 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 thirdparty
// This file contains tests for the storage classes API resource.
import (
"encoding/json"
"reflect"
"sort"
"sync"
"testing"
"time"
extensions "k8s.io/api/extensions/v1beta1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/diff"
"k8s.io/apimachinery/pkg/util/wait"
restclient "k8s.io/client-go/rest"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
"k8s.io/kubernetes/test/integration/framework"
)
func TestThirdPartyDiscovery(t *testing.T) {
group := "company.com"
version := "v1"
_, s, closeFn := framework.RunAMaster(framework.NewIntegrationTestMasterConfig())
defer closeFn()
clientConfig := &restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{NegotiatedSerializer: api.Codecs}}
client := clientset.NewForConfigOrDie(clientConfig)
// install thirdparty resource
once := sync.Once{}
deleteFoo := installThirdParty(t, client, clientConfig,
&extensions.ThirdPartyResource{
ObjectMeta: metav1.ObjectMeta{Name: "foo.company.com"},
Versions: []extensions.APIVersion{{Name: version}},
}, group, version, "foos",
)
defer once.Do(deleteFoo)
// check whether it shows up in discovery properly
resources, err := client.Discovery().ServerResourcesForGroupVersion("company.com/" + version)
if err != nil {
t.Fatal(err)
}
if len(resources.APIResources) != 1 {
t.Fatalf("Expected exactly the resource \"foos\" in group version %v/%v via discovery, got: %v", group, version, resources.APIResources)
}
r := resources.APIResources[0]
if r.Name != "foos" {
t.Fatalf("Expected exactly the resource \"foos\" in group version %v/%v via discovery, got: %v", group, version, r)
}
sort.Strings(r.Verbs)
expectedVerbs := []string{"create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"}
if !reflect.DeepEqual([]string(r.Verbs), expectedVerbs) {
t.Fatalf("Unexpected verbs for resource \"foos\" in group version %v/%v via discovery: expected=%v got=%v", group, version, expectedVerbs, r.Verbs)
}
// delete
once.Do(deleteFoo)
// check whether resource is also gone from discovery
resources, err = client.Discovery().ServerResourcesForGroupVersion(group + "/" + version)
if err == nil {
for _, r := range resources.APIResources {
if r.Name == "foos" {
t.Fatalf("unexpected resource \"foos\" in group version %v/%v after deletion", group, version)
}
}
}
}
// TODO these tests will eventually be runnable in a single test
func TestThirdPartyDelete(t *testing.T) {
_, s, closeFn := framework.RunAMaster(framework.NewIntegrationTestMasterConfig())
defer closeFn()
clientConfig := &restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{NegotiatedSerializer: api.Codecs}}
client := clientset.NewForConfigOrDie(clientConfig)
DoTestInstallThirdPartyAPIDelete(t, client, clientConfig)
}
func TestThirdPartyMultiple(t *testing.T) {
_, s, closeFn := framework.RunAMaster(framework.NewIntegrationTestMasterConfig())
defer closeFn()
clientConfig := &restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{NegotiatedSerializer: api.Codecs}}
client := clientset.NewForConfigOrDie(clientConfig)
DoTestInstallMultipleAPIs(t, client, clientConfig)
}
// TODO make multiple versions work. they've been broken
var versionsToTest = []string{"v1"}
type Foo struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty" description:"standard object metadata"`
SomeField string `json:"someField"`
OtherField int `json:"otherField"`
}
type FooList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty" description:"standard list metadata; see https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata"`
Items []Foo `json:"items"`
}
// installThirdParty installs a third party resource and returns a defer func
func installThirdParty(t *testing.T, client clientset.Interface, clientConfig *restclient.Config, tpr *extensions.ThirdPartyResource, group, version, resource string) func() {
var err error
_, err = client.Extensions().ThirdPartyResources().Create(tpr)
if err != nil {
t.Fatal(err)
}
fooClientConfig := *clientConfig
fooClientConfig.APIPath = "apis"
fooClientConfig.GroupVersion = &schema.GroupVersion{Group: group, Version: version}
fooClient, err := restclient.RESTClientFor(&fooClientConfig)
if err != nil {
t.Fatal(err)
}
err = wait.Poll(100*time.Millisecond, 60*time.Second, func() (bool, error) {
_, err := fooClient.Get().Namespace("default").Resource(resource).DoRaw()
if err == nil {
return true, nil
}
if apierrors.IsNotFound(err) {
return false, nil
}
return false, err
})
if err != nil {
t.Fatal(err)
}
return func() {
client.Extensions().ThirdPartyResources().Delete(tpr.Name, nil)
err = wait.Poll(100*time.Millisecond, 60*time.Second, func() (bool, error) {
_, err := fooClient.Get().Namespace("default").Resource(resource).DoRaw()
if apierrors.IsNotFound(err) {
return true, nil
}
return false, err
})
if err != nil {
t.Fatal(err)
}
}
}
func DoTestInstallMultipleAPIs(t *testing.T, client clientset.Interface, clientConfig *restclient.Config) {
group := "company.com"
version := "v1"
deleteFoo := installThirdParty(t, client, clientConfig,
&extensions.ThirdPartyResource{
ObjectMeta: metav1.ObjectMeta{Name: "foo.company.com"},
Versions: []extensions.APIVersion{{Name: version}},
}, group, version, "foos",
)
defer deleteFoo()
// TODO make multiple resources in one version work
// deleteBar = installThirdParty(t, client, clientConfig,
// &extensions.ThirdPartyResource{
// ObjectMeta: metav1.ObjectMeta{Name: "bar.company.com"},
// Versions: []extensions.APIVersion{{Name: version}},
// }, group, version, "bars",
// )
// defer deleteBar()
}
func DoTestInstallThirdPartyAPIDelete(t *testing.T, client clientset.Interface, clientConfig *restclient.Config) {
for _, version := range versionsToTest {
testInstallThirdPartyAPIDeleteVersion(t, client, clientConfig, version)
}
}
func testInstallThirdPartyAPIDeleteVersion(t *testing.T, client clientset.Interface, clientConfig *restclient.Config, version string) {
group := "company.com"
deleteFoo := installThirdParty(t, client, clientConfig,
&extensions.ThirdPartyResource{
ObjectMeta: metav1.ObjectMeta{Name: "foo.company.com"},
Versions: []extensions.APIVersion{{Name: version}},
}, group, version, "foos",
)
defer deleteFoo()
fooClientConfig := *clientConfig
fooClientConfig.APIPath = "apis"
fooClientConfig.GroupVersion = &schema.GroupVersion{Group: group, Version: version}
fooClient, err := restclient.RESTClientFor(&fooClientConfig)
if err != nil {
t.Fatal(err)
}
expectedObj := Foo{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: "default",
},
TypeMeta: metav1.TypeMeta{
Kind: "Foo",
},
SomeField: "test field",
OtherField: 10,
}
objBytes, err := json.Marshal(&expectedObj)
if err != nil {
t.Fatal(err)
}
if _, err := fooClient.Post().Namespace("default").Resource("foos").Body(objBytes).DoRaw(); err != nil {
t.Fatal(err)
}
apiBytes, err := fooClient.Get().Namespace("default").Resource("foos").Name("test").DoRaw()
if err != nil {
t.Fatal(err)
}
item := Foo{}
err = json.Unmarshal(apiBytes, &item)
if err != nil {
t.Fatal(err)
}
// Fill in fields set by the apiserver
item.SelfLink = expectedObj.SelfLink
item.ResourceVersion = expectedObj.ResourceVersion
item.Namespace = expectedObj.Namespace
item.UID = expectedObj.UID
item.CreationTimestamp = expectedObj.CreationTimestamp
if !reflect.DeepEqual(item, expectedObj) {
t.Fatalf("expected:\n%v\n", diff.ObjectGoPrintSideBySide(expectedObj, item))
}
listBytes, err := fooClient.Get().Namespace("default").Resource("foos").DoRaw()
if err != nil {
t.Fatal(err)
}
list := FooList{}
err = json.Unmarshal(listBytes, &list)
if err != nil {
t.Fatal(err)
}
if len(list.Items) != 1 {
t.Fatalf("wrong item: %v", list)
}
if _, err := fooClient.Delete().Namespace("default").Resource("foos").Name("test").DoRaw(); err != nil {
t.Fatal(err)
}
if _, err := fooClient.Get().Namespace("default").Resource("foos").Name("test").DoRaw(); !apierrors.IsNotFound(err) {
t.Fatal(err)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment