2016-07-07 11:40:12 +00:00
|
|
|
/*
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
2016-11-23 10:30:36 +00:00
|
|
|
package testutil
|
2016-07-07 11:40:12 +00:00
|
|
|
|
|
|
|
import (
|
2017-04-04 13:35:44 +00:00
|
|
|
"encoding/json"
|
2016-07-07 11:40:12 +00:00
|
|
|
"errors"
|
2016-08-14 01:41:20 +00:00
|
|
|
"fmt"
|
2018-05-12 07:15:57 +00:00
|
|
|
"reflect"
|
2016-07-07 11:40:12 +00:00
|
|
|
"sync"
|
2018-05-12 07:15:57 +00:00
|
|
|
"testing"
|
2016-08-14 01:41:20 +00:00
|
|
|
"time"
|
2016-07-07 11:40:12 +00:00
|
|
|
|
2017-01-13 17:48:50 +00:00
|
|
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
2017-01-25 13:13:07 +00:00
|
|
|
"k8s.io/apimachinery/pkg/api/resource"
|
2017-01-11 14:09:48 +00:00
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"k8s.io/apimachinery/pkg/runtime"
|
2017-01-16 20:13:59 +00:00
|
|
|
"k8s.io/apimachinery/pkg/types"
|
2017-01-11 14:09:48 +00:00
|
|
|
"k8s.io/apimachinery/pkg/util/sets"
|
2017-04-04 13:35:44 +00:00
|
|
|
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
2017-01-11 14:09:48 +00:00
|
|
|
"k8s.io/apimachinery/pkg/watch"
|
2017-02-13 10:48:34 +00:00
|
|
|
|
2017-06-22 18:24:23 +00:00
|
|
|
"k8s.io/apimachinery/pkg/util/clock"
|
2017-07-18 14:00:51 +00:00
|
|
|
ref "k8s.io/client-go/tools/reference"
|
2017-04-04 13:35:44 +00:00
|
|
|
|
2017-06-22 17:25:57 +00:00
|
|
|
"k8s.io/api/core/v1"
|
2017-06-23 20:56:37 +00:00
|
|
|
"k8s.io/client-go/kubernetes/fake"
|
|
|
|
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
|
2018-05-12 07:15:57 +00:00
|
|
|
"k8s.io/client-go/tools/cache"
|
2017-10-16 11:41:50 +00:00
|
|
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
2017-11-08 22:34:54 +00:00
|
|
|
api "k8s.io/kubernetes/pkg/apis/core"
|
2016-07-12 12:29:46 +00:00
|
|
|
utilnode "k8s.io/kubernetes/pkg/util/node"
|
2017-02-13 10:48:34 +00:00
|
|
|
|
2017-06-23 20:56:37 +00:00
|
|
|
jsonpatch "github.com/evanphx/json-patch"
|
2018-11-09 18:49:10 +00:00
|
|
|
"k8s.io/klog"
|
2016-07-07 11:40:12 +00:00
|
|
|
)
|
|
|
|
|
2018-05-12 07:15:57 +00:00
|
|
|
var (
|
|
|
|
keyFunc = cache.DeletionHandlingMetaNamespaceKeyFunc
|
|
|
|
)
|
|
|
|
|
2016-07-07 11:40:12 +00:00
|
|
|
// FakeNodeHandler is a fake implementation of NodesInterface and NodeInterface. It
|
|
|
|
// allows test cases to have fine-grained control over mock behaviors. We also need
|
2018-09-20 21:41:52 +00:00
|
|
|
// PodsInterface and PodInterface to test list & delete pods, which is implemented in
|
2016-07-07 11:40:12 +00:00
|
|
|
// the embedded client.Fake field.
|
|
|
|
type FakeNodeHandler struct {
|
|
|
|
*fake.Clientset
|
|
|
|
|
|
|
|
// Input: Hooks determine if request is valid or not
|
2016-11-18 20:50:17 +00:00
|
|
|
CreateHook func(*FakeNodeHandler, *v1.Node) bool
|
|
|
|
Existing []*v1.Node
|
2016-07-07 11:40:12 +00:00
|
|
|
|
|
|
|
// Output
|
2016-11-18 20:50:17 +00:00
|
|
|
CreatedNodes []*v1.Node
|
|
|
|
DeletedNodes []*v1.Node
|
|
|
|
UpdatedNodes []*v1.Node
|
|
|
|
UpdatedNodeStatuses []*v1.Node
|
2016-07-07 11:40:12 +00:00
|
|
|
RequestCount int
|
|
|
|
|
|
|
|
// Synchronization
|
|
|
|
lock sync.Mutex
|
2016-11-23 10:30:36 +00:00
|
|
|
DeleteWaitChan chan struct{}
|
2018-02-20 17:54:07 +00:00
|
|
|
PatchWaitChan chan struct{}
|
2016-07-07 11:40:12 +00:00
|
|
|
}
|
|
|
|
|
2018-09-20 21:41:52 +00:00
|
|
|
// FakeLegacyHandler is a fake implementation of CoreV1Interface.
|
2016-07-07 11:40:12 +00:00
|
|
|
type FakeLegacyHandler struct {
|
2016-11-18 20:50:17 +00:00
|
|
|
v1core.CoreV1Interface
|
2016-07-07 11:40:12 +00:00
|
|
|
n *FakeNodeHandler
|
|
|
|
}
|
|
|
|
|
2016-11-23 10:30:36 +00:00
|
|
|
// GetUpdatedNodesCopy returns a slice of Nodes with updates applied.
|
2017-08-04 23:34:28 +00:00
|
|
|
func (m *FakeNodeHandler) GetUpdatedNodesCopy() []*v1.Node {
|
|
|
|
m.lock.Lock()
|
|
|
|
defer m.lock.Unlock()
|
|
|
|
updatedNodesCopy := make([]*v1.Node, len(m.UpdatedNodes), len(m.UpdatedNodes))
|
|
|
|
for i, ptr := range m.UpdatedNodes {
|
2016-07-07 11:40:12 +00:00
|
|
|
updatedNodesCopy[i] = ptr
|
|
|
|
}
|
|
|
|
return updatedNodesCopy
|
|
|
|
}
|
|
|
|
|
2016-11-23 10:30:36 +00:00
|
|
|
// Core returns fake CoreInterface.
|
2017-08-04 23:34:28 +00:00
|
|
|
func (m *FakeNodeHandler) Core() v1core.CoreV1Interface {
|
|
|
|
return &FakeLegacyHandler{m.Clientset.Core(), m}
|
2016-07-07 11:40:12 +00:00
|
|
|
}
|
|
|
|
|
2017-03-29 23:21:42 +00:00
|
|
|
// CoreV1 returns fake CoreV1Interface
|
2017-08-04 23:34:28 +00:00
|
|
|
func (m *FakeNodeHandler) CoreV1() v1core.CoreV1Interface {
|
|
|
|
return &FakeLegacyHandler{m.Clientset.CoreV1(), m}
|
2017-03-29 23:21:42 +00:00
|
|
|
}
|
|
|
|
|
2016-11-23 10:30:36 +00:00
|
|
|
// Nodes return fake NodeInterfaces.
|
2016-11-18 20:50:17 +00:00
|
|
|
func (m *FakeLegacyHandler) Nodes() v1core.NodeInterface {
|
2016-07-07 11:40:12 +00:00
|
|
|
return m.n
|
|
|
|
}
|
|
|
|
|
2016-11-23 10:30:36 +00:00
|
|
|
// Create adds a new Node to the fake store.
|
2016-11-18 20:50:17 +00:00
|
|
|
func (m *FakeNodeHandler) Create(node *v1.Node) (*v1.Node, error) {
|
2016-07-07 11:40:12 +00:00
|
|
|
m.lock.Lock()
|
|
|
|
defer func() {
|
|
|
|
m.RequestCount++
|
|
|
|
m.lock.Unlock()
|
|
|
|
}()
|
|
|
|
for _, n := range m.Existing {
|
|
|
|
if n.Name == node.Name {
|
|
|
|
return nil, apierrors.NewAlreadyExists(api.Resource("nodes"), node.Name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if m.CreateHook == nil || m.CreateHook(m, node) {
|
|
|
|
nodeCopy := *node
|
|
|
|
m.CreatedNodes = append(m.CreatedNodes, &nodeCopy)
|
|
|
|
return node, nil
|
|
|
|
}
|
2017-08-04 23:34:28 +00:00
|
|
|
return nil, errors.New("create error")
|
2016-07-07 11:40:12 +00:00
|
|
|
}
|
|
|
|
|
2016-11-23 10:30:36 +00:00
|
|
|
// Get returns a Node from the fake store.
|
2016-12-07 13:26:33 +00:00
|
|
|
func (m *FakeNodeHandler) Get(name string, opts metav1.GetOptions) (*v1.Node, error) {
|
2016-07-07 11:40:12 +00:00
|
|
|
m.lock.Lock()
|
|
|
|
defer func() {
|
|
|
|
m.RequestCount++
|
|
|
|
m.lock.Unlock()
|
|
|
|
}()
|
2016-09-14 09:27:14 +00:00
|
|
|
for i := range m.UpdatedNodes {
|
|
|
|
if m.UpdatedNodes[i].Name == name {
|
|
|
|
nodeCopy := *m.UpdatedNodes[i]
|
|
|
|
return &nodeCopy, nil
|
|
|
|
}
|
|
|
|
}
|
2016-07-07 11:40:12 +00:00
|
|
|
for i := range m.Existing {
|
|
|
|
if m.Existing[i].Name == name {
|
|
|
|
nodeCopy := *m.Existing[i]
|
|
|
|
return &nodeCopy, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2016-11-23 10:30:36 +00:00
|
|
|
// List returns a list of Nodes from the fake store.
|
2017-01-22 03:36:02 +00:00
|
|
|
func (m *FakeNodeHandler) List(opts metav1.ListOptions) (*v1.NodeList, error) {
|
2016-07-07 11:40:12 +00:00
|
|
|
m.lock.Lock()
|
|
|
|
defer func() {
|
|
|
|
m.RequestCount++
|
|
|
|
m.lock.Unlock()
|
|
|
|
}()
|
2016-11-18 20:50:17 +00:00
|
|
|
var nodes []*v1.Node
|
2016-07-07 11:40:12 +00:00
|
|
|
for i := 0; i < len(m.UpdatedNodes); i++ {
|
|
|
|
if !contains(m.UpdatedNodes[i], m.DeletedNodes) {
|
|
|
|
nodes = append(nodes, m.UpdatedNodes[i])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for i := 0; i < len(m.Existing); i++ {
|
|
|
|
if !contains(m.Existing[i], m.DeletedNodes) && !contains(m.Existing[i], nodes) {
|
|
|
|
nodes = append(nodes, m.Existing[i])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for i := 0; i < len(m.CreatedNodes); i++ {
|
2016-08-18 09:30:26 +00:00
|
|
|
if !contains(m.CreatedNodes[i], m.DeletedNodes) && !contains(m.CreatedNodes[i], nodes) {
|
2016-07-07 11:40:12 +00:00
|
|
|
nodes = append(nodes, m.CreatedNodes[i])
|
|
|
|
}
|
|
|
|
}
|
2016-11-18 20:50:17 +00:00
|
|
|
nodeList := &v1.NodeList{}
|
2016-07-07 11:40:12 +00:00
|
|
|
for _, node := range nodes {
|
|
|
|
nodeList.Items = append(nodeList.Items, *node)
|
|
|
|
}
|
|
|
|
return nodeList, nil
|
|
|
|
}
|
|
|
|
|
2018-09-20 21:41:52 +00:00
|
|
|
// Delete deletes a Node from the fake store.
|
2017-01-24 15:38:21 +00:00
|
|
|
func (m *FakeNodeHandler) Delete(id string, opt *metav1.DeleteOptions) error {
|
2016-07-07 11:40:12 +00:00
|
|
|
m.lock.Lock()
|
|
|
|
defer func() {
|
|
|
|
m.RequestCount++
|
2016-11-23 10:30:36 +00:00
|
|
|
if m.DeleteWaitChan != nil {
|
|
|
|
m.DeleteWaitChan <- struct{}{}
|
2016-07-07 11:40:12 +00:00
|
|
|
}
|
|
|
|
m.lock.Unlock()
|
|
|
|
}()
|
2016-11-23 10:30:36 +00:00
|
|
|
m.DeletedNodes = append(m.DeletedNodes, NewNode(id))
|
2016-07-07 11:40:12 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-11-23 10:30:36 +00:00
|
|
|
// DeleteCollection deletes a collection of Nodes from the fake store.
|
2017-01-24 15:38:21 +00:00
|
|
|
func (m *FakeNodeHandler) DeleteCollection(opt *metav1.DeleteOptions, listOpts metav1.ListOptions) error {
|
2016-07-07 11:40:12 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-11-23 10:30:36 +00:00
|
|
|
// Update updates a Node in the fake store.
|
2016-11-18 20:50:17 +00:00
|
|
|
func (m *FakeNodeHandler) Update(node *v1.Node) (*v1.Node, error) {
|
2016-07-07 11:40:12 +00:00
|
|
|
m.lock.Lock()
|
|
|
|
defer func() {
|
|
|
|
m.RequestCount++
|
|
|
|
m.lock.Unlock()
|
|
|
|
}()
|
2017-04-04 13:35:44 +00:00
|
|
|
|
2016-07-07 11:40:12 +00:00
|
|
|
nodeCopy := *node
|
2016-09-14 09:27:14 +00:00
|
|
|
for i, updateNode := range m.UpdatedNodes {
|
|
|
|
if updateNode.Name == nodeCopy.Name {
|
|
|
|
m.UpdatedNodes[i] = &nodeCopy
|
|
|
|
return node, nil
|
|
|
|
}
|
|
|
|
}
|
2016-07-07 11:40:12 +00:00
|
|
|
m.UpdatedNodes = append(m.UpdatedNodes, &nodeCopy)
|
|
|
|
return node, nil
|
|
|
|
}
|
|
|
|
|
2016-11-23 10:30:36 +00:00
|
|
|
// UpdateStatus updates a status of a Node in the fake store.
|
2016-11-18 20:50:17 +00:00
|
|
|
func (m *FakeNodeHandler) UpdateStatus(node *v1.Node) (*v1.Node, error) {
|
2016-07-07 11:40:12 +00:00
|
|
|
m.lock.Lock()
|
|
|
|
defer func() {
|
|
|
|
m.RequestCount++
|
|
|
|
m.lock.Unlock()
|
|
|
|
}()
|
2017-04-04 13:35:44 +00:00
|
|
|
|
|
|
|
var origNodeCopy v1.Node
|
|
|
|
found := false
|
|
|
|
for i := range m.Existing {
|
|
|
|
if m.Existing[i].Name == node.Name {
|
|
|
|
origNodeCopy = *m.Existing[i]
|
|
|
|
found = true
|
2017-05-19 09:06:17 +00:00
|
|
|
break
|
2017-04-04 13:35:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
updatedNodeIndex := -1
|
|
|
|
for i := range m.UpdatedNodes {
|
|
|
|
if m.UpdatedNodes[i].Name == node.Name {
|
|
|
|
origNodeCopy = *m.UpdatedNodes[i]
|
|
|
|
updatedNodeIndex = i
|
|
|
|
found = true
|
2017-05-19 09:06:17 +00:00
|
|
|
break
|
2017-04-04 13:35:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !found {
|
|
|
|
return nil, fmt.Errorf("Not found node %v", node)
|
|
|
|
}
|
|
|
|
|
|
|
|
origNodeCopy.Status = node.Status
|
|
|
|
if updatedNodeIndex < 0 {
|
|
|
|
m.UpdatedNodes = append(m.UpdatedNodes, &origNodeCopy)
|
|
|
|
} else {
|
|
|
|
m.UpdatedNodes[updatedNodeIndex] = &origNodeCopy
|
|
|
|
}
|
|
|
|
|
2016-07-07 11:40:12 +00:00
|
|
|
nodeCopy := *node
|
|
|
|
m.UpdatedNodeStatuses = append(m.UpdatedNodeStatuses, &nodeCopy)
|
|
|
|
return node, nil
|
|
|
|
}
|
|
|
|
|
2016-11-23 10:30:36 +00:00
|
|
|
// PatchStatus patches a status of a Node in the fake store.
|
2016-11-18 20:50:17 +00:00
|
|
|
func (m *FakeNodeHandler) PatchStatus(nodeName string, data []byte) (*v1.Node, error) {
|
2016-07-07 11:40:12 +00:00
|
|
|
m.RequestCount++
|
2018-06-13 11:58:41 +00:00
|
|
|
return m.Patch(nodeName, types.StrategicMergePatchType, data, "status")
|
2016-07-07 11:40:12 +00:00
|
|
|
}
|
|
|
|
|
2016-11-23 10:30:36 +00:00
|
|
|
// Watch watches Nodes in a fake store.
|
2017-01-22 03:36:02 +00:00
|
|
|
func (m *FakeNodeHandler) Watch(opts metav1.ListOptions) (watch.Interface, error) {
|
2016-09-23 16:01:58 +00:00
|
|
|
return watch.NewFake(), nil
|
2016-07-07 11:40:12 +00:00
|
|
|
}
|
|
|
|
|
2016-11-23 10:30:36 +00:00
|
|
|
// Patch patches a Node in the fake store.
|
2017-01-16 20:13:59 +00:00
|
|
|
func (m *FakeNodeHandler) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (*v1.Node, error) {
|
2017-04-04 13:35:44 +00:00
|
|
|
m.lock.Lock()
|
|
|
|
defer func() {
|
|
|
|
m.RequestCount++
|
2018-02-20 17:54:07 +00:00
|
|
|
if m.PatchWaitChan != nil {
|
|
|
|
m.PatchWaitChan <- struct{}{}
|
|
|
|
}
|
2017-04-04 13:35:44 +00:00
|
|
|
m.lock.Unlock()
|
|
|
|
}()
|
|
|
|
var nodeCopy v1.Node
|
|
|
|
for i := range m.Existing {
|
|
|
|
if m.Existing[i].Name == name {
|
|
|
|
nodeCopy = *m.Existing[i]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
updatedNodeIndex := -1
|
|
|
|
for i := range m.UpdatedNodes {
|
|
|
|
if m.UpdatedNodes[i].Name == name {
|
|
|
|
nodeCopy = *m.UpdatedNodes[i]
|
|
|
|
updatedNodeIndex = i
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
originalObjJS, err := json.Marshal(nodeCopy)
|
|
|
|
if err != nil {
|
2018-11-09 18:49:10 +00:00
|
|
|
klog.Errorf("Failed to marshal %v", nodeCopy)
|
2017-04-04 13:35:44 +00:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
var originalNode v1.Node
|
|
|
|
if err = json.Unmarshal(originalObjJS, &originalNode); err != nil {
|
2018-11-09 18:49:10 +00:00
|
|
|
klog.Errorf("Failed to unmarshal original object: %v", err)
|
2017-04-04 13:35:44 +00:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var patchedObjJS []byte
|
|
|
|
switch pt {
|
|
|
|
case types.JSONPatchType:
|
|
|
|
patchObj, err := jsonpatch.DecodePatch(data)
|
|
|
|
if err != nil {
|
2018-11-09 18:49:10 +00:00
|
|
|
klog.Error(err.Error())
|
2017-04-04 13:35:44 +00:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
if patchedObjJS, err = patchObj.Apply(originalObjJS); err != nil {
|
2018-11-09 18:49:10 +00:00
|
|
|
klog.Error(err.Error())
|
2017-04-04 13:35:44 +00:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
case types.MergePatchType:
|
|
|
|
if patchedObjJS, err = jsonpatch.MergePatch(originalObjJS, data); err != nil {
|
2018-11-09 18:49:10 +00:00
|
|
|
klog.Error(err.Error())
|
2017-04-04 13:35:44 +00:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
case types.StrategicMergePatchType:
|
|
|
|
if patchedObjJS, err = strategicpatch.StrategicMergePatch(originalObjJS, data, originalNode); err != nil {
|
2018-11-09 18:49:10 +00:00
|
|
|
klog.Error(err.Error())
|
2017-04-04 13:35:44 +00:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
default:
|
2018-11-09 18:49:10 +00:00
|
|
|
klog.Errorf("unknown Content-Type header for patch: %v", pt)
|
2017-04-04 13:35:44 +00:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var updatedNode v1.Node
|
|
|
|
if err = json.Unmarshal(patchedObjJS, &updatedNode); err != nil {
|
2018-11-09 18:49:10 +00:00
|
|
|
klog.Errorf("Failed to unmarshal patched object: %v", err)
|
2017-04-04 13:35:44 +00:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if updatedNodeIndex < 0 {
|
|
|
|
m.UpdatedNodes = append(m.UpdatedNodes, &updatedNode)
|
|
|
|
} else {
|
|
|
|
m.UpdatedNodes[updatedNodeIndex] = &updatedNode
|
|
|
|
}
|
|
|
|
|
|
|
|
return &updatedNode, nil
|
2016-07-07 11:40:12 +00:00
|
|
|
}
|
|
|
|
|
2016-08-14 01:41:20 +00:00
|
|
|
// FakeRecorder is used as a fake during testing.
|
|
|
|
type FakeRecorder struct {
|
2017-02-13 10:48:34 +00:00
|
|
|
sync.Mutex
|
2017-07-15 05:25:54 +00:00
|
|
|
source v1.EventSource
|
|
|
|
Events []*v1.Event
|
2016-08-14 01:41:20 +00:00
|
|
|
clock clock.Clock
|
|
|
|
}
|
|
|
|
|
2016-11-23 10:30:36 +00:00
|
|
|
// Event emits a fake event to the fake recorder
|
2016-08-14 01:41:20 +00:00
|
|
|
func (f *FakeRecorder) Event(obj runtime.Object, eventtype, reason, message string) {
|
2016-12-03 18:57:26 +00:00
|
|
|
f.generateEvent(obj, metav1.Now(), eventtype, reason, message)
|
2016-08-14 01:41:20 +00:00
|
|
|
}
|
|
|
|
|
2016-11-23 10:30:36 +00:00
|
|
|
// Eventf emits a fake formatted event to the fake recorder
|
2016-08-14 01:41:20 +00:00
|
|
|
func (f *FakeRecorder) Eventf(obj runtime.Object, eventtype, reason, messageFmt string, args ...interface{}) {
|
|
|
|
f.Event(obj, eventtype, reason, fmt.Sprintf(messageFmt, args...))
|
|
|
|
}
|
|
|
|
|
2016-11-23 10:30:36 +00:00
|
|
|
// PastEventf is a no-op
|
2016-12-03 18:57:26 +00:00
|
|
|
func (f *FakeRecorder) PastEventf(obj runtime.Object, timestamp metav1.Time, eventtype, reason, messageFmt string, args ...interface{}) {
|
2016-08-14 01:41:20 +00:00
|
|
|
}
|
|
|
|
|
2018-05-23 23:12:54 +00:00
|
|
|
// AnnotatedEventf emits a fake formatted event to the fake recorder
|
|
|
|
func (f *FakeRecorder) AnnotatedEventf(obj runtime.Object, annotations map[string]string, eventtype, reason, messageFmt string, args ...interface{}) {
|
|
|
|
f.Eventf(obj, eventtype, reason, messageFmt, args)
|
|
|
|
}
|
|
|
|
|
2016-12-03 18:57:26 +00:00
|
|
|
func (f *FakeRecorder) generateEvent(obj runtime.Object, timestamp metav1.Time, eventtype, reason, message string) {
|
2017-02-13 10:48:34 +00:00
|
|
|
f.Lock()
|
|
|
|
defer f.Unlock()
|
2017-10-16 11:41:50 +00:00
|
|
|
ref, err := ref.GetReference(legacyscheme.Scheme, obj)
|
2016-08-14 01:41:20 +00:00
|
|
|
if err != nil {
|
2018-11-09 18:49:10 +00:00
|
|
|
klog.Errorf("Encountered error while getting reference: %v", err)
|
2016-08-14 01:41:20 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
event := f.makeEvent(ref, eventtype, reason, message)
|
|
|
|
event.Source = f.source
|
2016-11-23 10:30:36 +00:00
|
|
|
if f.Events != nil {
|
|
|
|
f.Events = append(f.Events, event)
|
2016-08-14 01:41:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-15 05:25:54 +00:00
|
|
|
func (f *FakeRecorder) makeEvent(ref *v1.ObjectReference, eventtype, reason, message string) *v1.Event {
|
2016-12-03 18:57:26 +00:00
|
|
|
t := metav1.Time{Time: f.clock.Now()}
|
2016-08-14 01:41:20 +00:00
|
|
|
namespace := ref.Namespace
|
|
|
|
if namespace == "" {
|
2017-01-22 03:36:02 +00:00
|
|
|
namespace = metav1.NamespaceDefault
|
2016-08-14 01:41:20 +00:00
|
|
|
}
|
2017-01-30 18:39:54 +00:00
|
|
|
|
2017-07-15 05:25:54 +00:00
|
|
|
clientref := v1.ObjectReference{
|
2017-01-30 18:39:54 +00:00
|
|
|
Kind: ref.Kind,
|
|
|
|
Namespace: ref.Namespace,
|
|
|
|
Name: ref.Name,
|
|
|
|
UID: ref.UID,
|
|
|
|
APIVersion: ref.APIVersion,
|
|
|
|
ResourceVersion: ref.ResourceVersion,
|
|
|
|
FieldPath: ref.FieldPath,
|
|
|
|
}
|
|
|
|
|
2017-07-15 05:25:54 +00:00
|
|
|
return &v1.Event{
|
2017-01-17 03:38:19 +00:00
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
2016-08-14 01:41:20 +00:00
|
|
|
Name: fmt.Sprintf("%v.%x", ref.Name, t.UnixNano()),
|
|
|
|
Namespace: namespace,
|
|
|
|
},
|
2017-01-30 18:39:54 +00:00
|
|
|
InvolvedObject: clientref,
|
2016-08-14 01:41:20 +00:00
|
|
|
Reason: reason,
|
|
|
|
Message: message,
|
|
|
|
FirstTimestamp: t,
|
|
|
|
LastTimestamp: t,
|
|
|
|
Count: 1,
|
|
|
|
Type: eventtype,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-23 10:30:36 +00:00
|
|
|
// NewFakeRecorder returns a pointer to a newly constructed FakeRecorder.
|
2016-08-14 01:41:20 +00:00
|
|
|
func NewFakeRecorder() *FakeRecorder {
|
|
|
|
return &FakeRecorder{
|
2017-07-15 05:25:54 +00:00
|
|
|
source: v1.EventSource{Component: "nodeControllerTest"},
|
|
|
|
Events: []*v1.Event{},
|
2016-08-14 01:41:20 +00:00
|
|
|
clock: clock.NewFakeClock(time.Now()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-23 10:30:36 +00:00
|
|
|
// NewNode is a helper function for creating Nodes for testing.
|
|
|
|
func NewNode(name string) *v1.Node {
|
2016-11-18 20:50:17 +00:00
|
|
|
return &v1.Node{
|
2017-01-17 03:38:19 +00:00
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: name},
|
2016-11-18 20:50:17 +00:00
|
|
|
Status: v1.NodeStatus{
|
|
|
|
Capacity: v1.ResourceList{
|
|
|
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
|
|
|
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10G"),
|
2016-07-07 11:40:12 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-23 10:30:36 +00:00
|
|
|
// NewPod is a helper function for creating Pods for testing.
|
|
|
|
func NewPod(name, host string) *v1.Pod {
|
2016-11-18 20:50:17 +00:00
|
|
|
pod := &v1.Pod{
|
2017-01-17 03:38:19 +00:00
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
2016-07-07 11:40:12 +00:00
|
|
|
Namespace: "default",
|
|
|
|
Name: name,
|
|
|
|
},
|
2016-11-18 20:50:17 +00:00
|
|
|
Spec: v1.PodSpec{
|
2016-07-07 11:40:12 +00:00
|
|
|
NodeName: host,
|
|
|
|
},
|
2016-11-18 20:50:17 +00:00
|
|
|
Status: v1.PodStatus{
|
|
|
|
Conditions: []v1.PodCondition{
|
2016-07-07 11:40:12 +00:00
|
|
|
{
|
2016-11-18 20:50:17 +00:00
|
|
|
Type: v1.PodReady,
|
|
|
|
Status: v1.ConditionTrue,
|
2016-07-07 11:40:12 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
return pod
|
|
|
|
}
|
|
|
|
|
2016-11-18 20:50:17 +00:00
|
|
|
func contains(node *v1.Node, nodes []*v1.Node) bool {
|
2016-07-07 11:40:12 +00:00
|
|
|
for i := 0; i < len(nodes); i++ {
|
|
|
|
if node.Name == nodes[i].Name {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2016-07-12 12:29:46 +00:00
|
|
|
|
2016-11-23 10:30:36 +00:00
|
|
|
// GetZones returns list of zones for all Nodes stored in FakeNodeHandler
|
|
|
|
func GetZones(nodeHandler *FakeNodeHandler) []string {
|
2017-01-22 03:36:02 +00:00
|
|
|
nodes, _ := nodeHandler.List(metav1.ListOptions{})
|
2016-07-12 12:29:46 +00:00
|
|
|
zones := sets.NewString()
|
|
|
|
for _, node := range nodes.Items {
|
|
|
|
zones.Insert(utilnode.GetZoneKey(&node))
|
|
|
|
}
|
|
|
|
return zones.List()
|
|
|
|
}
|
2016-07-13 14:57:22 +00:00
|
|
|
|
2016-11-23 10:30:36 +00:00
|
|
|
// CreateZoneID returns a single zoneID for a given region and zone.
|
|
|
|
func CreateZoneID(region, zone string) string {
|
2016-07-13 14:57:22 +00:00
|
|
|
return region + ":\x00:" + zone
|
|
|
|
}
|
2018-05-12 07:15:57 +00:00
|
|
|
|
|
|
|
// GetKey is a helper function used by controllers unit tests to get the
|
|
|
|
// key for a given kubernetes resource.
|
|
|
|
func GetKey(obj interface{}, t *testing.T) string {
|
|
|
|
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
|
|
|
if ok {
|
|
|
|
// if tombstone , try getting the value from tombstone.Obj
|
|
|
|
obj = tombstone.Obj
|
|
|
|
}
|
|
|
|
val := reflect.ValueOf(obj).Elem()
|
|
|
|
name := val.FieldByName("Name").String()
|
|
|
|
kind := val.FieldByName("Kind").String()
|
|
|
|
// Note kind is not always set in the tests, so ignoring that for now
|
|
|
|
if len(name) == 0 || len(kind) == 0 {
|
|
|
|
t.Errorf("Unexpected object %v", obj)
|
|
|
|
}
|
|
|
|
|
|
|
|
key, err := keyFunc(obj)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Unexpected error getting key for %v %v: %v", kind, name, err)
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return key
|
|
|
|
}
|