Updated ContextData and PluginContext with Clone methods.

This is necessary to be able to clone PluginContext during preemption.
This commit is contained in:
Abdullah Gharaibeh 2019-09-23 14:34:40 -04:00
parent 26cc580e65
commit 641317bdde
4 changed files with 98 additions and 4 deletions

View File

@ -37,6 +37,17 @@ func (mc CommunicatingPlugin) Name() string {
return Name
}
type contextData struct {
data string
}
func (f *contextData) Clone() framework.ContextData {
copy := &contextData{
data: f.data,
}
return copy
}
// Reserve is the functions invoked by the framework at "reserve" extension point.
func (mc CommunicatingPlugin) Reserve(pc *framework.PluginContext, pod *v1.Pod, nodeName string) *framework.Status {
if pod == nil {
@ -44,7 +55,7 @@ func (mc CommunicatingPlugin) Reserve(pc *framework.PluginContext, pod *v1.Pod,
}
if pod.Name == "my-test-pod" {
pc.Lock()
pc.Write(framework.ContextKey(pod.Name), "never bind")
pc.Write(framework.ContextKey(pod.Name), &contextData{data: "never bind"})
pc.Unlock()
}
return nil
@ -57,8 +68,10 @@ func (mc CommunicatingPlugin) PreBind(pc *framework.PluginContext, pod *v1.Pod,
}
pc.RLock()
defer pc.RUnlock()
if v, e := pc.Read(framework.ContextKey(pod.Name)); e == nil && v == "never bind" {
return framework.NewStatus(framework.Unschedulable, "pod is not permitted")
if v, e := pc.Read(framework.ContextKey(pod.Name)); e == nil {
if value, ok := v.(*contextData); ok && value.data == "never bind" {
return framework.NewStatus(framework.Unschedulable, "pod is not permitted")
}
}
return nil
}

View File

@ -43,6 +43,7 @@ filegroup(
go_test(
name = "go_default_test",
srcs = [
"context_test.go",
"framework_test.go",
"interface_test.go",
"registry_test.go",

View File

@ -27,7 +27,12 @@ const (
)
// ContextData is a generic type for arbitrary data stored in PluginContext.
type ContextData interface{}
type ContextData interface {
// Clone is an interface to make a copy of ContextData. For performance reasons,
// clone should make shallow copies for members (e.g., slices or maps) that are not
// impacted by PreFilter's optional AddPod/RemovePod methods.
Clone() ContextData
}
// ContextKey is the type of keys stored in PluginContext.
type ContextKey string
@ -48,6 +53,15 @@ func NewPluginContext() *PluginContext {
}
}
// Clone creates a copy of PluginContext and returns its pointer.
func (c *PluginContext) Clone() *PluginContext {
copy := NewPluginContext()
for k, v := range c.storage {
copy.Write(k, v.Clone())
}
return copy
}
// Read retrieves data with the given "key" from PluginContext. If the key is not
// present an error is returned.
// This function is not thread safe. In multi-threaded code, lock should be

View File

@ -0,0 +1,66 @@
/*
Copyright 2019 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 v1alpha1
import (
"testing"
)
type fakeData struct {
data string
}
func (f *fakeData) Clone() ContextData {
copy := &fakeData{
data: f.data,
}
return copy
}
func TestPluginContextClone(t *testing.T) {
var key ContextKey = "key"
data1 := "value1"
data2 := "value2"
pc := NewPluginContext()
originalValue := &fakeData{
data: data1,
}
pc.Write(key, originalValue)
pcCopy := pc.Clone()
valueCopy, err := pcCopy.Read(key)
if err != nil {
t.Errorf("failed to read copied value: %v", err)
}
if v, ok := valueCopy.(*fakeData); ok && v.data != data1 {
t.Errorf("clone failed, got %q, expected %q", v.data, data1)
}
originalValue.data = data2
original, err := pc.Read(key)
if err != nil {
t.Errorf("failed to read original value: %v", err)
}
if v, ok := original.(*fakeData); ok && v.data != data2 {
t.Errorf("original value should change, got %q, expected %q", v.data, data2)
}
if v, ok := valueCopy.(*fakeData); ok && v.data != data1 {
t.Errorf("cloned copy should not change, got %q, expected %q", v.data, data1)
}
}