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
4d235063
Commit
4d235063
authored
Jul 01, 2016
by
Chao Xu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
only store typeMeta and objectMeta in the gc store
parent
d52204a1
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
399 additions
and
38 deletions
+399
-38
controllermanager.go
cmd/kube-controller-manager/app/controllermanager.go
+8
-2
apiserver_test.go
pkg/apiserver/apiserver_test.go
+4
-0
client.go
pkg/client/typed/dynamic/client.go
+7
-9
client_pool.go
pkg/client/typed/dynamic/client_pool.go
+9
-0
garbagecollector.go
pkg/controller/garbagecollector/garbagecollector.go
+55
-13
garbagecollector_test.go
pkg/controller/garbagecollector/garbagecollector_test.go
+18
-5
metaonly.go
pkg/controller/garbagecollector/metaonly/metaonly.go
+64
-0
metaonly_test.go
pkg/controller/garbagecollector/metaonly/metaonly_test.go
+163
-0
types.generated.go
pkg/controller/garbagecollector/metaonly/types.generated.go
+0
-0
types.go
pkg/controller/garbagecollector/metaonly/types.go
+40
-0
namespace_controller_test.go
pkg/controller/namespace/namespace_controller_test.go
+1
-1
namespace_controller_utils.go
pkg/controller/namespace/namespace_controller_utils.go
+5
-1
codec.go
pkg/runtime/codec.go
+5
-3
scheme.go
pkg/runtime/scheme.go
+5
-0
unstructured.go
pkg/runtime/unstructured.go
+1
-0
dynamic_client_test.go
test/integration/client/dynamic_client_test.go
+5
-1
garbage_collector_test.go
test/integration/garbagecollector/garbage_collector_test.go
+9
-3
No files found.
cmd/kube-controller-manager/app/controllermanager.go
View file @
4d235063
...
...
@@ -51,6 +51,7 @@ import (
endpointcontroller
"k8s.io/kubernetes/pkg/controller/endpoint"
"k8s.io/kubernetes/pkg/controller/framework/informers"
"k8s.io/kubernetes/pkg/controller/garbagecollector"
"k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly"
"k8s.io/kubernetes/pkg/controller/job"
namespacecontroller
"k8s.io/kubernetes/pkg/controller/namespace"
nodecontroller
"k8s.io/kubernetes/pkg/controller/node"
...
...
@@ -69,6 +70,7 @@ import (
persistentvolumecontroller
"k8s.io/kubernetes/pkg/controller/volume/persistentvolume"
"k8s.io/kubernetes/pkg/healthz"
quotainstall
"k8s.io/kubernetes/pkg/quota/install"
"k8s.io/kubernetes/pkg/runtime/serializer"
"k8s.io/kubernetes/pkg/serviceaccount"
"k8s.io/kubernetes/pkg/util/configz"
"k8s.io/kubernetes/pkg/util/crypto"
...
...
@@ -495,8 +497,12 @@ func StartControllers(s *options.CMServer, kubeClient *client.Client, kubeconfig
if
err
!=
nil
{
glog
.
Fatalf
(
"Failed to get supported resources from server: %v"
,
err
)
}
clientPool
:=
dynamic
.
NewClientPool
(
restclient
.
AddUserAgent
(
kubeconfig
,
"generic-garbage-collector"
),
dynamic
.
LegacyAPIPathResolverFunc
)
garbageCollector
,
err
:=
garbagecollector
.
NewGarbageCollector
(
clientPool
,
groupVersionResources
)
config
:=
restclient
.
AddUserAgent
(
kubeconfig
,
"generic-garbage-collector"
)
config
.
ContentConfig
.
NegotiatedSerializer
=
serializer
.
DirectCodecFactory
{
CodecFactory
:
metaonly
.
NewMetadataCodecFactory
()}
metaOnlyClientPool
:=
dynamic
.
NewClientPool
(
config
,
dynamic
.
LegacyAPIPathResolverFunc
)
config
.
ContentConfig
.
NegotiatedSerializer
=
nil
clientPool
:=
dynamic
.
NewClientPool
(
config
,
dynamic
.
LegacyAPIPathResolverFunc
)
garbageCollector
,
err
:=
garbagecollector
.
NewGarbageCollector
(
metaOnlyClientPool
,
clientPool
,
groupVersionResources
)
if
err
!=
nil
{
glog
.
Errorf
(
"Failed to start the generic garbage collector: %v"
,
err
)
}
else
{
...
...
pkg/apiserver/apiserver_test.go
View file @
4d235063
...
...
@@ -1911,6 +1911,7 @@ func TestDeleteWithOptions(t *testing.T) {
if
simpleStorage
.
deleted
!=
ID
{
t
.
Errorf
(
"Unexpected delete: %s, expected %s"
,
simpleStorage
.
deleted
,
ID
)
}
simpleStorage
.
deleteOptions
.
GetObjectKind
()
.
SetGroupVersionKind
(
unversioned
.
GroupVersionKind
{})
if
!
api
.
Semantic
.
DeepEqual
(
simpleStorage
.
deleteOptions
,
item
)
{
t
.
Errorf
(
"unexpected delete options: %s"
,
diff
.
ObjectDiff
(
simpleStorage
.
deleteOptions
,
item
))
}
...
...
@@ -2700,6 +2701,7 @@ func TestCreate(t *testing.T) {
t
.
Errorf
(
"unexpected error: %v %#v"
,
err
,
response
)
}
itemOut
.
GetObjectKind
()
.
SetGroupVersionKind
(
unversioned
.
GroupVersionKind
{})
if
!
reflect
.
DeepEqual
(
&
itemOut
,
simple
)
{
t
.
Errorf
(
"Unexpected data: %#v, expected %#v (%s)"
,
itemOut
,
simple
,
string
(
body
))
}
...
...
@@ -2769,6 +2771,7 @@ func TestCreateYAML(t *testing.T) {
t
.
Fatalf
(
"unexpected error: %v %#v"
,
err
,
response
)
}
itemOut
.
GetObjectKind
()
.
SetGroupVersionKind
(
unversioned
.
GroupVersionKind
{})
if
!
reflect
.
DeepEqual
(
&
itemOut
,
simple
)
{
t
.
Errorf
(
"Unexpected data: %#v, expected %#v (%s)"
,
itemOut
,
simple
,
string
(
body
))
}
...
...
@@ -2827,6 +2830,7 @@ func TestCreateInNamespace(t *testing.T) {
t
.
Fatalf
(
"unexpected error: %v
\n
%s"
,
err
,
data
)
}
itemOut
.
GetObjectKind
()
.
SetGroupVersionKind
(
unversioned
.
GroupVersionKind
{})
if
!
reflect
.
DeepEqual
(
&
itemOut
,
simple
)
{
t
.
Errorf
(
"Unexpected data: %#v, expected %#v (%s)"
,
itemOut
,
simple
,
string
(
body
))
}
...
...
pkg/client/typed/dynamic/client.go
View file @
4d235063
...
...
@@ -54,13 +54,9 @@ func NewClient(conf *restclient.Config) (*Client, error) {
confCopy
:=
*
conf
conf
=
&
confCopy
codec
:=
dynamicCodec
{}
// TODO: it's questionable that this should be using anything other than unstructured schema and JSON
conf
.
ContentType
=
runtime
.
ContentTypeJSON
conf
.
AcceptContentTypes
=
runtime
.
ContentTypeJSON
streamingInfo
,
_
:=
api
.
Codecs
.
StreamingSerializerForMediaType
(
"application/json;stream=watch"
,
nil
)
conf
.
NegotiatedSerializer
=
serializer
.
NegotiatedSerializerWrapper
(
runtime
.
SerializerInfo
{
Serializer
:
codec
},
streamingInfo
)
if
conf
.
APIPath
==
""
{
conf
.
APIPath
=
"/api"
...
...
@@ -69,6 +65,10 @@ func NewClient(conf *restclient.Config) (*Client, error) {
if
len
(
conf
.
UserAgent
)
==
0
{
conf
.
UserAgent
=
restclient
.
DefaultKubernetesUserAgent
()
}
if
conf
.
NegotiatedSerializer
==
nil
{
streamingInfo
,
_
:=
api
.
Codecs
.
StreamingSerializerForMediaType
(
"application/json;stream=watch"
,
nil
)
conf
.
NegotiatedSerializer
=
serializer
.
NegotiatedSerializerWrapper
(
runtime
.
SerializerInfo
{
Serializer
:
dynamicCodec
{}},
streamingInfo
)
}
cl
,
err
:=
restclient
.
RESTClientFor
(
conf
)
if
err
!=
nil
{
...
...
@@ -119,19 +119,17 @@ type ResourceClient struct {
}
// List returns a list of objects for this resource.
func
(
rc
*
ResourceClient
)
List
(
opts
runtime
.
Object
)
(
*
runtime
.
UnstructuredList
,
error
)
{
result
:=
new
(
runtime
.
UnstructuredList
)
func
(
rc
*
ResourceClient
)
List
(
opts
runtime
.
Object
)
(
runtime
.
Object
,
error
)
{
parameterEncoder
:=
rc
.
parameterCodec
if
parameterEncoder
==
nil
{
parameterEncoder
=
defaultParameterEncoder
}
err
:=
rc
.
cl
.
Get
()
.
return
rc
.
cl
.
Get
()
.
NamespaceIfScoped
(
rc
.
ns
,
rc
.
resource
.
Namespaced
)
.
Resource
(
rc
.
resource
.
Name
)
.
VersionedParams
(
opts
,
parameterEncoder
)
.
Do
()
.
Into
(
result
)
return
result
,
err
Get
()
}
// Get gets the resource with the specified name.
...
...
pkg/client/typed/dynamic/client_pool.go
View file @
4d235063
...
...
@@ -19,8 +19,11 @@ package dynamic
import
(
"sync"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/client/restclient"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/runtime/serializer"
)
// ClientPool manages a pool of dynamic clients.
...
...
@@ -77,6 +80,12 @@ func (c *clientPoolImpl) ClientForGroupVersion(groupVersion unversioned.GroupVer
// we need to make a client
conf
.
GroupVersion
=
&
groupVersion
if
conf
.
NegotiatedSerializer
==
nil
{
streamingInfo
,
_
:=
api
.
Codecs
.
StreamingSerializerForMediaType
(
"application/json;stream=watch"
,
nil
)
conf
.
NegotiatedSerializer
=
serializer
.
NegotiatedSerializerWrapper
(
runtime
.
SerializerInfo
{
Serializer
:
dynamicCodec
{}},
streamingInfo
)
}
dynamicClient
,
err
:=
NewClient
(
conf
)
if
err
!=
nil
{
return
nil
,
err
...
...
pkg/controller/garbagecollector/garbagecollector.go
View file @
4d235063
...
...
@@ -33,6 +33,7 @@ import (
"k8s.io/kubernetes/pkg/client/cache"
"k8s.io/kubernetes/pkg/client/typed/dynamic"
"k8s.io/kubernetes/pkg/controller/framework"
"k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/types"
utilerrors
"k8s.io/kubernetes/pkg/util/errors"
...
...
@@ -154,6 +155,7 @@ func (p *Propagator) addDependentToOwners(n *node, owners []metatypes.OwnerRefer
dependentsLock
:
&
sync
.
RWMutex
{},
dependents
:
make
(
map
[
*
node
]
struct
{}),
}
glog
.
V
(
6
)
.
Infof
(
"add virtual node.identity: %s
\n\n
"
,
ownerNode
.
identity
)
p
.
uidToNode
.
Write
(
ownerNode
)
p
.
gc
.
dirtyQueue
.
Add
(
ownerNode
)
}
...
...
@@ -426,7 +428,12 @@ func (p *Propagator) processEvent() {
// removing ownerReferences from the dependents if the owner is deleted with
// DeleteOptions.OrphanDependents=true.
type
GarbageCollector
struct
{
restMapper
meta
.
RESTMapper
restMapper
meta
.
RESTMapper
// metaOnlyClientPool uses a special codec, which removes fields except for
// apiVersion, kind, and metadata during decoding.
metaOnlyClientPool
dynamic
.
ClientPool
// clientPool uses the regular dynamicCodec. We need it to update
// finalizers. It can be removed if we support patching finalizers.
clientPool
dynamic
.
ClientPool
dirtyQueue
*
workqueue
.
Type
orphanQueue
*
workqueue
.
Type
...
...
@@ -434,8 +441,6 @@ type GarbageCollector struct {
propagator
*
Propagator
}
// TODO: make special List and Watch function that removes fields other than
// ObjectMeta.
func
gcListWatcher
(
client
*
dynamic
.
Client
,
resource
unversioned
.
GroupVersionResource
)
*
cache
.
ListWatch
{
return
&
cache
.
ListWatch
{
ListFunc
:
func
(
options
api
.
ListOptions
)
(
runtime
.
Object
,
error
)
{
...
...
@@ -461,14 +466,21 @@ func gcListWatcher(client *dynamic.Client, resource unversioned.GroupVersionReso
}
}
func
monitorFor
(
p
*
Propagator
,
clientPool
dynamic
.
ClientPool
,
resource
unversioned
.
GroupVersionResource
)
(
monitor
,
error
)
{
func
monitorFor
(
p
*
Propagator
,
clientPool
dynamic
.
ClientPool
,
resource
unversioned
.
GroupVersionResource
,
kind
unversioned
.
GroupVersionKind
)
(
monitor
,
error
)
{
// TODO: consider store in one storage.
glog
.
V
(
6
)
.
Infof
(
"create storage for resource %s"
,
resource
)
var
monitor
monitor
client
,
err
:=
c
lientPool
.
ClientForGroupVersion
(
resource
.
GroupVersion
())
client
,
err
:=
p
.
gc
.
metaOnlyC
lientPool
.
ClientForGroupVersion
(
resource
.
GroupVersion
())
if
err
!=
nil
{
return
monitor
,
err
}
setObjectTypeMeta
:=
func
(
obj
interface
{})
{
runtimeObject
,
ok
:=
obj
.
(
runtime
.
Object
)
if
!
ok
{
utilruntime
.
HandleError
(
fmt
.
Errorf
(
"expected runtime.Object, got %#v"
,
obj
))
}
runtimeObject
.
GetObjectKind
()
.
SetGroupVersionKind
(
kind
)
}
monitor
.
store
,
monitor
.
controller
=
framework
.
NewInformer
(
gcListWatcher
(
client
,
resource
),
nil
,
...
...
@@ -476,6 +488,7 @@ func monitorFor(p *Propagator, clientPool dynamic.ClientPool, resource unversion
framework
.
ResourceEventHandlerFuncs
{
// add the event to the propagator's eventQueue.
AddFunc
:
func
(
obj
interface
{})
{
setObjectTypeMeta
(
obj
)
event
:=
event
{
eventType
:
addEvent
,
obj
:
obj
,
...
...
@@ -483,6 +496,8 @@ func monitorFor(p *Propagator, clientPool dynamic.ClientPool, resource unversion
p
.
eventQueue
.
Add
(
event
)
},
UpdateFunc
:
func
(
oldObj
,
newObj
interface
{})
{
setObjectTypeMeta
(
newObj
)
setObjectTypeMeta
(
oldObj
)
event
:=
event
{
updateEvent
,
newObj
,
oldObj
}
p
.
eventQueue
.
Add
(
event
)
},
...
...
@@ -491,6 +506,7 @@ func monitorFor(p *Propagator, clientPool dynamic.ClientPool, resource unversion
if
deletedFinalStateUnknown
,
ok
:=
obj
.
(
cache
.
DeletedFinalStateUnknown
);
ok
{
obj
=
deletedFinalStateUnknown
.
Obj
}
setObjectTypeMeta
(
obj
)
event
:=
event
{
eventType
:
deleteEvent
,
obj
:
obj
,
...
...
@@ -511,11 +527,12 @@ var ignoredResources = map[unversioned.GroupVersionResource]struct{}{
unversioned
.
GroupVersionResource
{
Group
:
"authorization.k8s.io"
,
Version
:
"v1beta1"
,
Resource
:
"subjectaccessreviews"
}
:
{},
}
func
NewGarbageCollector
(
clientPool
dynamic
.
ClientPool
,
resources
[]
unversioned
.
GroupVersionResource
)
(
*
GarbageCollector
,
error
)
{
func
NewGarbageCollector
(
metaOnlyClientPool
dynamic
.
ClientPool
,
clientPool
dynamic
.
ClientPool
,
resources
[]
unversioned
.
GroupVersionResource
)
(
*
GarbageCollector
,
error
)
{
gc
:=
&
GarbageCollector
{
clientPool
:
clientPool
,
dirtyQueue
:
workqueue
.
New
(),
orphanQueue
:
workqueue
.
New
(),
metaOnlyClientPool
:
metaOnlyClientPool
,
clientPool
:
clientPool
,
dirtyQueue
:
workqueue
.
New
(),
orphanQueue
:
workqueue
.
New
(),
// TODO: should use a dynamic RESTMapper built from the discovery results.
restMapper
:
registered
.
RESTMapper
(),
}
...
...
@@ -532,7 +549,11 @@ func NewGarbageCollector(clientPool dynamic.ClientPool, resources []unversioned.
glog
.
V
(
6
)
.
Infof
(
"ignore resource %#v"
,
resource
)
continue
}
monitor
,
err
:=
monitorFor
(
gc
.
propagator
,
gc
.
clientPool
,
resource
)
kind
,
err
:=
gc
.
restMapper
.
KindFor
(
resource
)
if
err
!=
nil
{
return
nil
,
err
}
monitor
,
err
:=
monitorFor
(
gc
.
propagator
,
gc
.
clientPool
,
resource
,
kind
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -549,7 +570,7 @@ func (gc *GarbageCollector) worker() {
defer
gc
.
dirtyQueue
.
Done
(
key
)
err
:=
gc
.
processItem
(
key
.
(
*
node
))
if
err
!=
nil
{
utilruntime
.
HandleError
(
fmt
.
Errorf
(
"Error syncing item %v: %v"
,
key
,
err
))
utilruntime
.
HandleError
(
fmt
.
Errorf
(
"Error syncing item %
#
v: %v"
,
key
,
err
))
}
}
...
...
@@ -623,6 +644,20 @@ func objectReferenceToUnstructured(ref objectReference) *runtime.Unstructured {
return
ret
}
func
objectReferenceToMetadataOnlyObject
(
ref
objectReference
)
*
metaonly
.
MetadataOnlyObject
{
return
&
metaonly
.
MetadataOnlyObject
{
TypeMeta
:
unversioned
.
TypeMeta
{
APIVersion
:
ref
.
APIVersion
,
Kind
:
ref
.
Kind
,
},
ObjectMeta
:
v1
.
ObjectMeta
{
Namespace
:
ref
.
Namespace
,
UID
:
ref
.
UID
,
Name
:
ref
.
Name
,
},
}
}
func
(
gc
*
GarbageCollector
)
processItem
(
item
*
node
)
error
{
// Get the latest item from the API server
latest
,
err
:=
gc
.
getObject
(
item
.
identity
)
...
...
@@ -634,15 +669,22 @@ func (gc *GarbageCollector) processItem(item *node) error {
glog
.
V
(
6
)
.
Infof
(
"item %v not found, generating a virtual delete event"
,
item
.
identity
)
event
:=
event
{
eventType
:
deleteEvent
,
obj
:
objectReferenceTo
Unstructured
(
item
.
identity
),
obj
:
objectReferenceTo
MetadataOnlyObject
(
item
.
identity
),
}
glog
.
V
(
6
)
.
Infof
(
"generating virtual delete event for %s
\n\n
"
,
event
.
obj
)
gc
.
propagator
.
eventQueue
.
Add
(
event
)
return
nil
}
return
err
}
if
latest
.
GetUID
()
!=
item
.
identity
.
UID
{
glog
.
V
(
6
)
.
Infof
(
"UID doesn't match, item %v not found, ignore it"
,
item
.
identity
)
glog
.
V
(
6
)
.
Infof
(
"UID doesn't match, item %v not found, generating a virtual delete event"
,
item
.
identity
)
event
:=
event
{
eventType
:
deleteEvent
,
obj
:
objectReferenceToMetadataOnlyObject
(
item
.
identity
),
}
glog
.
V
(
6
)
.
Infof
(
"generating virtual delete event for %s
\n\n
"
,
event
.
obj
)
gc
.
propagator
.
eventQueue
.
Add
(
event
)
return
nil
}
ownerReferences
:=
latest
.
GetOwnerReferences
()
...
...
pkg/controller/garbagecollector/garbagecollector_test.go
View file @
4d235063
...
...
@@ -24,6 +24,8 @@ import (
"testing"
_
"k8s.io/kubernetes/pkg/api/install"
"k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly"
"k8s.io/kubernetes/pkg/runtime/serializer"
"github.com/stretchr/testify/assert"
"k8s.io/kubernetes/pkg/api"
...
...
@@ -39,9 +41,13 @@ import (
)
func
TestNewGarbageCollector
(
t
*
testing
.
T
)
{
clientPool
:=
dynamic
.
NewClientPool
(
&
restclient
.
Config
{},
dynamic
.
LegacyAPIPathResolverFunc
)
config
:=
&
restclient
.
Config
{}
config
.
ContentConfig
.
NegotiatedSerializer
=
serializer
.
DirectCodecFactory
{
CodecFactory
:
metaonly
.
NewMetadataCodecFactory
()}
metaOnlyClientPool
:=
dynamic
.
NewClientPool
(
config
,
dynamic
.
LegacyAPIPathResolverFunc
)
config
.
ContentConfig
.
NegotiatedSerializer
=
nil
clientPool
:=
dynamic
.
NewClientPool
(
config
,
dynamic
.
LegacyAPIPathResolverFunc
)
podResource
:=
[]
unversioned
.
GroupVersionResource
{{
Version
:
"v1"
,
Resource
:
"pods"
}}
gc
,
err
:=
NewGarbageCollector
(
clientPool
,
podResource
)
gc
,
err
:=
NewGarbageCollector
(
metaOnlyClientPool
,
clientPool
,
podResource
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
...
...
@@ -141,8 +147,11 @@ func TestProcessItem(t *testing.T) {
podResource
:=
[]
unversioned
.
GroupVersionResource
{{
Version
:
"v1"
,
Resource
:
"pods"
}}
srv
,
clientConfig
:=
testServerAndClientConfig
(
testHandler
.
ServeHTTP
)
defer
srv
.
Close
()
clientConfig
.
ContentConfig
.
NegotiatedSerializer
=
serializer
.
DirectCodecFactory
{
CodecFactory
:
metaonly
.
NewMetadataCodecFactory
()}
metaOnlyClientPool
:=
dynamic
.
NewClientPool
(
clientConfig
,
dynamic
.
LegacyAPIPathResolverFunc
)
clientConfig
.
ContentConfig
.
NegotiatedSerializer
=
nil
clientPool
:=
dynamic
.
NewClientPool
(
clientConfig
,
dynamic
.
LegacyAPIPathResolverFunc
)
gc
,
err
:=
NewGarbageCollector
(
clientPool
,
podResource
)
gc
,
err
:=
NewGarbageCollector
(
metaOnlyClientPool
,
clientPool
,
podResource
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
...
...
@@ -293,9 +302,13 @@ func TestProcessEvent(t *testing.T) {
// TestDependentsRace relies on golang's data race detector to check if there is
// data race among in the dependents field.
func
TestDependentsRace
(
t
*
testing
.
T
)
{
clientPool
:=
dynamic
.
NewClientPool
(
&
restclient
.
Config
{},
dynamic
.
LegacyAPIPathResolverFunc
)
config
:=
&
restclient
.
Config
{}
config
.
ContentConfig
.
NegotiatedSerializer
=
serializer
.
DirectCodecFactory
{
CodecFactory
:
metaonly
.
NewMetadataCodecFactory
()}
metaOnlyClientPool
:=
dynamic
.
NewClientPool
(
config
,
dynamic
.
LegacyAPIPathResolverFunc
)
config
.
ContentConfig
.
NegotiatedSerializer
=
nil
clientPool
:=
dynamic
.
NewClientPool
(
config
,
dynamic
.
LegacyAPIPathResolverFunc
)
podResource
:=
[]
unversioned
.
GroupVersionResource
{{
Version
:
"v1"
,
Resource
:
"pods"
}}
gc
,
err
:=
NewGarbageCollector
(
clientPool
,
podResource
)
gc
,
err
:=
NewGarbageCollector
(
metaOnlyClientPool
,
clientPool
,
podResource
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
...
...
pkg/controller/garbagecollector/metaonly/metaonly.go
0 → 100644
View file @
4d235063
/*
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
metaonly
import
(
"fmt"
"strings"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/runtime/serializer"
)
func
(
obj
*
MetadataOnlyObject
)
GetObjectKind
()
unversioned
.
ObjectKind
{
return
obj
}
func
(
obj
*
MetadataOnlyObjectList
)
GetObjectKind
()
unversioned
.
ObjectKind
{
return
obj
}
type
metaOnlyJSONScheme
struct
{}
// This function can be extended to mapping different gvk to different MetadataOnlyObject,
// which embedded with different version of ObjectMeta. Currently the system
// only supports v1.ObjectMeta.
func
gvkToMetadataOnlyObject
(
gvk
unversioned
.
GroupVersionKind
)
runtime
.
Object
{
if
strings
.
HasSuffix
(
gvk
.
Kind
,
"List"
)
{
return
&
MetadataOnlyObjectList
{}
}
else
{
return
&
MetadataOnlyObject
{}
}
}
func
NewMetadataCodecFactory
()
serializer
.
CodecFactory
{
// populating another scheme from api.Scheme, registering every kind with
// MetadataOnlyObject (or MetadataOnlyObjectList).
scheme
:=
runtime
.
NewScheme
()
allTypes
:=
api
.
Scheme
.
AllKnownTypes
()
for
kind
:=
range
allTypes
{
if
kind
.
Version
==
runtime
.
APIVersionInternal
{
continue
}
metaOnlyObject
:=
gvkToMetadataOnlyObject
(
kind
)
scheme
.
AddKnownTypeWithName
(
kind
,
metaOnlyObject
)
}
scheme
.
AddUnversionedTypes
(
api
.
Unversioned
,
&
unversioned
.
Status
{})
return
serializer
.
NewCodecFactory
(
scheme
)
}
// String converts a MetadataOnlyObject to a human-readable string.
func
(
metaOnly
MetadataOnlyObject
)
String
()
string
{
return
fmt
.
Sprintf
(
"%s/%s, name: %s, DeletionTimestamp:%v"
,
metaOnly
.
TypeMeta
.
APIVersion
,
metaOnly
.
TypeMeta
.
Kind
,
metaOnly
.
ObjectMeta
.
Name
,
metaOnly
.
ObjectMeta
.
DeletionTimestamp
)
}
pkg/controller/garbagecollector/metaonly/metaonly_test.go
0 → 100644
View file @
4d235063
/*
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
metaonly
import
(
"encoding/json"
"reflect"
"testing"
_
"k8s.io/kubernetes/pkg/api/install"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/runtime/serializer"
)
func
getPod
()
*
v1
.
Pod
{
return
&
v1
.
Pod
{
TypeMeta
:
unversioned
.
TypeMeta
{
Kind
:
"Pod"
,
APIVersion
:
"v1"
,
},
ObjectMeta
:
v1
.
ObjectMeta
{
Name
:
"pod"
,
OwnerReferences
:
[]
v1
.
OwnerReference
{
{
UID
:
"1234"
},
},
},
Spec
:
v1
.
PodSpec
{
Containers
:
[]
v1
.
Container
{
{
Name
:
"fake-name"
,
Image
:
"fakeimage"
,
},
},
},
}
}
func
getPodJson
(
t
*
testing
.
T
)
[]
byte
{
data
,
err
:=
json
.
Marshal
(
getPod
())
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
return
data
}
func
getPodListJson
(
t
*
testing
.
T
)
[]
byte
{
data
,
err
:=
json
.
Marshal
(
&
v1
.
PodList
{
TypeMeta
:
unversioned
.
TypeMeta
{
Kind
:
"PodList"
,
APIVersion
:
"v1"
,
},
Items
:
[]
v1
.
Pod
{
*
getPod
(),
*
getPod
(),
},
})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
return
data
}
func
verfiyMetadata
(
description
string
,
t
*
testing
.
T
,
in
*
MetadataOnlyObject
)
{
pod
:=
getPod
()
if
e
,
a
:=
pod
.
ObjectMeta
,
in
.
ObjectMeta
;
!
reflect
.
DeepEqual
(
e
,
a
)
{
t
.
Errorf
(
"%s: expected %#v, got %#v"
,
description
,
e
,
a
)
}
}
func
TestDecodeToMetadataOnlyObject
(
t
*
testing
.
T
)
{
data
:=
getPodJson
(
t
)
cf
:=
serializer
.
DirectCodecFactory
{
CodecFactory
:
NewMetadataCodecFactory
()}
serializer
,
ok
:=
cf
.
SerializerForMediaType
(
runtime
.
ContentTypeJSON
,
nil
)
if
!
ok
{
t
.
Fatalf
(
"expected to get a JSON serializer"
)
}
codec
:=
cf
.
DecoderToVersion
(
serializer
,
unversioned
.
GroupVersion
{
Group
:
"SOMEGROUP"
,
Version
:
"SOMEVERSION"
})
// decode with into
into
:=
&
MetadataOnlyObject
{}
ret
,
_
,
err
:=
codec
.
Decode
(
data
,
nil
,
into
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
metaOnly
,
ok
:=
ret
.
(
*
MetadataOnlyObject
)
if
!
ok
{
t
.
Fatalf
(
"expected ret to be *runtime.MetadataOnlyObject"
)
}
verfiyMetadata
(
"check returned metaonly with into"
,
t
,
metaOnly
)
verfiyMetadata
(
"check into"
,
t
,
into
)
// decode without into
ret
,
_
,
err
=
codec
.
Decode
(
data
,
nil
,
nil
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
metaOnly
,
ok
=
ret
.
(
*
MetadataOnlyObject
)
if
!
ok
{
t
.
Fatalf
(
"expected ret to be *runtime.MetadataOnlyObject"
)
}
verfiyMetadata
(
"check returned metaonly without into"
,
t
,
metaOnly
)
}
func
verifyListMetadata
(
t
*
testing
.
T
,
metaOnlyList
*
MetadataOnlyObjectList
)
{
items
,
err
:=
meta
.
ExtractList
(
metaOnlyList
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
for
_
,
item
:=
range
items
{
metaOnly
,
ok
:=
item
.
(
*
MetadataOnlyObject
)
if
!
ok
{
t
.
Fatalf
(
"expected item to be *MetadataOnlyObject"
)
}
verfiyMetadata
(
"check list"
,
t
,
metaOnly
)
}
}
func
TestDecodeToMetadataOnlyObjectList
(
t
*
testing
.
T
)
{
data
:=
getPodListJson
(
t
)
cf
:=
serializer
.
DirectCodecFactory
{
CodecFactory
:
NewMetadataCodecFactory
()}
serializer
,
ok
:=
cf
.
SerializerForMediaType
(
runtime
.
ContentTypeJSON
,
nil
)
if
!
ok
{
t
.
Fatalf
(
"expected to get a JSON serializer"
)
}
codec
:=
cf
.
DecoderToVersion
(
serializer
,
unversioned
.
GroupVersion
{
Group
:
"SOMEGROUP"
,
Version
:
"SOMEVERSION"
})
// decode with into
into
:=
&
MetadataOnlyObjectList
{}
ret
,
_
,
err
:=
codec
.
Decode
(
data
,
nil
,
into
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
metaOnlyList
,
ok
:=
ret
.
(
*
MetadataOnlyObjectList
)
if
!
ok
{
t
.
Fatalf
(
"expected ret to be *runtime.UnstructuredList"
)
}
verifyListMetadata
(
t
,
metaOnlyList
)
verifyListMetadata
(
t
,
into
)
// decode without into
ret
,
_
,
err
=
codec
.
Decode
(
data
,
nil
,
nil
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
metaOnlyList
,
ok
=
ret
.
(
*
MetadataOnlyObjectList
)
if
!
ok
{
t
.
Fatalf
(
"expected ret to be *runtime.UnstructuredList"
)
}
verifyListMetadata
(
t
,
metaOnlyList
)
}
pkg/controller/garbagecollector/metaonly/types.generated.go
0 → 100644
View file @
4d235063
This diff is collapsed.
Click to expand it.
pkg/controller/garbagecollector/metaonly/types.go
0 → 100644
View file @
4d235063
/*
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
metaonly
import
(
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1"
)
// MetadataOnlyObject allows decoding only the apiVersion, kind, and metadata fields of
// JSON data.
// TODO: enable meta-only decoding for protobuf.
type
MetadataOnlyObject
struct
{
unversioned
.
TypeMeta
`json:",inline"`
v1
.
ObjectMeta
`json:"metadata,omitempty"`
}
// MetadataOnlyObjectList allows decoding from JSON data only the typemeta and metadata of
// a list, and those of the enclosing objects.
// TODO: enable meta-only decoding for protobuf.
type
MetadataOnlyObjectList
struct
{
unversioned
.
TypeMeta
`json:",inline"`
unversioned
.
ListMeta
`json:"metadata,omitempty"`
Items
[]
MetadataOnlyObject
`json:"items"`
}
pkg/controller/namespace/namespace_controller_test.go
View file @
4d235063
...
...
@@ -272,7 +272,7 @@ func (f *fakeActionHandler) ServeHTTP(response http.ResponseWriter, request *htt
f
.
actions
=
append
(
f
.
actions
,
fakeAction
{
method
:
request
.
Method
,
path
:
request
.
URL
.
Path
})
response
.
Header
()
.
Set
(
"Content-Type"
,
runtime
.
ContentTypeJSON
)
response
.
WriteHeader
(
f
.
statusCode
)
response
.
Write
([]
byte
(
"{
\"
kind
\"
:
\"
List
\"
}"
))
response
.
Write
([]
byte
(
"{
\"
kind
\"
:
\"
List
\"
,
\"
items
\"
:null
}"
))
}
// testGroupVersionResources returns a mocked up set of resources across different api groups for testing namespace controller.
...
...
pkg/controller/namespace/namespace_controller_utils.go
View file @
4d235063
...
...
@@ -195,8 +195,12 @@ func listCollection(
}
apiResource
:=
unversioned
.
APIResource
{
Name
:
gvr
.
Resource
,
Namespaced
:
true
}
unstructuredList
,
err
:=
dynamicClient
.
Resource
(
&
apiResource
,
namespace
)
.
List
(
&
v1
.
ListOptions
{})
obj
,
err
:=
dynamicClient
.
Resource
(
&
apiResource
,
namespace
)
.
List
(
&
v1
.
ListOptions
{})
if
err
==
nil
{
unstructuredList
,
ok
:=
obj
.
(
*
runtime
.
UnstructuredList
)
if
!
ok
{
return
nil
,
false
,
fmt
.
Errorf
(
"resource: %s, expected *runtime.UnstructuredList, got %#v"
,
apiResource
.
Name
,
obj
)
}
return
unstructuredList
,
true
,
nil
}
...
...
pkg/runtime/codec.go
View file @
4d235063
...
...
@@ -80,12 +80,14 @@ func EncodeOrDie(e Encoder, obj Object) string {
// invokes the ObjectCreator to instantiate a new gvk. Returns an error if the typer cannot find the object.
func
UseOrCreateObject
(
t
ObjectTyper
,
c
ObjectCreater
,
gvk
unversioned
.
GroupVersionKind
,
obj
Object
)
(
Object
,
error
)
{
if
obj
!=
nil
{
into
,
_
,
err
:=
t
.
ObjectKinds
(
obj
)
kinds
,
_
,
err
:=
t
.
ObjectKinds
(
obj
)
if
err
!=
nil
{
return
nil
,
err
}
if
gvk
==
into
[
0
]
{
return
obj
,
nil
for
_
,
kind
:=
range
kinds
{
if
gvk
==
kind
{
return
obj
,
nil
}
}
}
return
c
.
New
(
gvk
)
...
...
pkg/runtime/scheme.go
View file @
4d235063
...
...
@@ -211,6 +211,11 @@ func (s *Scheme) KnownTypes(gv unversioned.GroupVersion) map[string]reflect.Type
return
types
}
// AllKnownTypes returns the all known types.
func
(
s
*
Scheme
)
AllKnownTypes
()
map
[
unversioned
.
GroupVersionKind
]
reflect
.
Type
{
return
s
.
gvkToType
}
// ObjectKind returns the group,version,kind of the go object and true if this object
// is considered unversioned, or an error if it's not a pointer or is unregistered.
func
(
s
*
Scheme
)
ObjectKind
(
obj
Object
)
(
unversioned
.
GroupVersionKind
,
bool
,
error
)
{
...
...
pkg/runtime/unstructured.go
View file @
4d235063
...
...
@@ -95,6 +95,7 @@ func (s unstructuredJSONScheme) decode(data []byte) (Object, error) {
err
:=
s
.
decodeToUnstructured
(
data
,
unstruct
)
return
unstruct
,
err
}
func
(
s
unstructuredJSONScheme
)
decodeInto
(
data
[]
byte
,
obj
Object
)
error
{
switch
x
:=
obj
.
(
type
)
{
case
*
Unstructured
:
...
...
test/integration/client/dynamic_client_test.go
View file @
4d235063
...
...
@@ -92,7 +92,11 @@ func TestDynamicClient(t *testing.T) {
}
// check dynamic list
unstructuredList
,
err
:=
dynamicClient
.
Resource
(
&
resource
,
ns
.
Name
)
.
List
(
&
v1
.
ListOptions
{})
obj
,
err
:=
dynamicClient
.
Resource
(
&
resource
,
ns
.
Name
)
.
List
(
&
v1
.
ListOptions
{})
unstructuredList
,
ok
:=
obj
.
(
*
runtime
.
UnstructuredList
)
if
!
ok
{
t
.
Fatalf
(
"expected *runtime.UnstructuredList, got %#v"
,
obj
)
}
if
err
!=
nil
{
t
.
Fatalf
(
"unexpected error when listing pods: %v"
,
err
)
}
...
...
test/integration/garbagecollector/garbage_collector_test.go
View file @
4d235063
...
...
@@ -35,7 +35,9 @@ import (
"k8s.io/kubernetes/pkg/client/restclient"
"k8s.io/kubernetes/pkg/client/typed/dynamic"
"k8s.io/kubernetes/pkg/controller/garbagecollector"
"k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly"
"k8s.io/kubernetes/pkg/registry/generic/registry"
"k8s.io/kubernetes/pkg/runtime/serializer"
"k8s.io/kubernetes/pkg/types"
"k8s.io/kubernetes/pkg/util/wait"
"k8s.io/kubernetes/test/integration/framework"
...
...
@@ -127,8 +129,12 @@ func setup(t *testing.T) (*httptest.Server, *garbagecollector.GarbageCollector,
if
err
!=
nil
{
t
.
Fatalf
(
"Failed to get supported resources from server: %v"
,
err
)
}
clientPool
:=
dynamic
.
NewClientPool
(
&
restclient
.
Config
{
Host
:
s
.
URL
},
dynamic
.
LegacyAPIPathResolverFunc
)
gc
,
err
:=
garbagecollector
.
NewGarbageCollector
(
clientPool
,
groupVersionResources
)
config
:=
&
restclient
.
Config
{
Host
:
s
.
URL
}
config
.
ContentConfig
.
NegotiatedSerializer
=
serializer
.
DirectCodecFactory
{
CodecFactory
:
metaonly
.
NewMetadataCodecFactory
()}
metaOnlyClientPool
:=
dynamic
.
NewClientPool
(
config
,
dynamic
.
LegacyAPIPathResolverFunc
)
config
.
ContentConfig
.
NegotiatedSerializer
=
nil
clientPool
:=
dynamic
.
NewClientPool
(
config
,
dynamic
.
LegacyAPIPathResolverFunc
)
gc
,
err
:=
garbagecollector
.
NewGarbageCollector
(
metaOnlyClientPool
,
clientPool
,
groupVersionResources
)
if
err
!=
nil
{
t
.
Fatalf
(
"Failed to create garbage collector"
)
}
...
...
@@ -215,7 +221,7 @@ func TestCascadingDeletion(t *testing.T) {
// sometimes the deletion of the RC takes long time to be observed by
// the gc, so wait for the garbage collector to observe the deletion of
// the toBeDeletedRC
if
err
:=
wait
.
Poll
(
10
*
time
.
Second
,
12
0
*
time
.
Second
,
func
()
(
bool
,
error
)
{
if
err
:=
wait
.
Poll
(
10
*
time
.
Second
,
6
0
*
time
.
Second
,
func
()
(
bool
,
error
)
{
return
!
gc
.
GraphHasUID
([]
types
.
UID
{
toBeDeletedRC
.
ObjectMeta
.
UID
}),
nil
});
err
!=
nil
{
t
.
Fatal
(
err
)
...
...
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