mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 20:53:33 +00:00
Remove pods from pkg/registry/etcd/etcd.go since they are in their own type
Altered the master initialization code
This commit is contained in:
parent
247e467217
commit
7a93af57c0
@ -117,19 +117,9 @@ type Config struct {
|
|||||||
// Master contains state for a Kubernetes cluster master/api server.
|
// Master contains state for a Kubernetes cluster master/api server.
|
||||||
type Master struct {
|
type Master struct {
|
||||||
// "Inputs", Copied from Config
|
// "Inputs", Copied from Config
|
||||||
controllerRegistry controller.Registry
|
client *client.Client
|
||||||
serviceRegistry service.Registry
|
portalNet *net.IPNet
|
||||||
endpointRegistry endpoint.Registry
|
cacheTimeout time.Duration
|
||||||
minionRegistry minion.Registry
|
|
||||||
eventRegistry generic.Registry
|
|
||||||
limitRangeRegistry generic.Registry
|
|
||||||
resourceQuotaRegistry resourcequota.Registry
|
|
||||||
namespaceRegistry generic.Registry
|
|
||||||
boundPodFactory pod.BoundPodFactory
|
|
||||||
storage map[string]apiserver.RESTStorage
|
|
||||||
client *client.Client
|
|
||||||
portalNet *net.IPNet
|
|
||||||
cacheTimeout time.Duration
|
|
||||||
|
|
||||||
mux apiserver.Mux
|
mux apiserver.Mux
|
||||||
muxHelper *apiserver.MuxHelper
|
muxHelper *apiserver.MuxHelper
|
||||||
@ -156,6 +146,17 @@ type Master struct {
|
|||||||
serviceReadWritePort int
|
serviceReadWritePort int
|
||||||
masterServices *util.Runner
|
masterServices *util.Runner
|
||||||
|
|
||||||
|
// storage contains the RESTful endpoints exposed by this master
|
||||||
|
storage map[string]apiserver.RESTStorage
|
||||||
|
|
||||||
|
// registries are internal client APIs for accessing the storage layer
|
||||||
|
// TODO: define the internal typed interface in a way that clients can
|
||||||
|
// also be replaced
|
||||||
|
nodeRegistry minion.Registry
|
||||||
|
namespaceRegistry generic.Registry
|
||||||
|
serviceRegistry service.Registry
|
||||||
|
endpointRegistry endpoint.Registry
|
||||||
|
|
||||||
// "Outputs"
|
// "Outputs"
|
||||||
Handler http.Handler
|
Handler http.Handler
|
||||||
InsecureHandler http.Handler
|
InsecureHandler http.Handler
|
||||||
@ -259,7 +260,6 @@ func setDefaults(c *Config) {
|
|||||||
// any unhandled paths to "Handler".
|
// any unhandled paths to "Handler".
|
||||||
func New(c *Config) *Master {
|
func New(c *Config) *Master {
|
||||||
setDefaults(c)
|
setDefaults(c)
|
||||||
boundPodFactory := &pod.BasicBoundPodFactory{}
|
|
||||||
if c.KubeletClient == nil {
|
if c.KubeletClient == nil {
|
||||||
glog.Fatalf("master.New() called with config.KubeletClient == nil")
|
glog.Fatalf("master.New() called with config.KubeletClient == nil")
|
||||||
}
|
}
|
||||||
@ -276,15 +276,6 @@ func New(c *Config) *Master {
|
|||||||
glog.Infof("Setting master service IPs based on PortalNet subnet to %q (read-only) and %q (read-write).", serviceReadOnlyIP, serviceReadWriteIP)
|
glog.Infof("Setting master service IPs based on PortalNet subnet to %q (read-only) and %q (read-write).", serviceReadOnlyIP, serviceReadWriteIP)
|
||||||
|
|
||||||
m := &Master{
|
m := &Master{
|
||||||
controllerRegistry: etcd.NewRegistry(c.EtcdHelper, nil),
|
|
||||||
serviceRegistry: etcd.NewRegistry(c.EtcdHelper, nil),
|
|
||||||
endpointRegistry: etcd.NewRegistry(c.EtcdHelper, nil),
|
|
||||||
eventRegistry: event.NewEtcdRegistry(c.EtcdHelper, uint64(c.EventTTL.Seconds())),
|
|
||||||
namespaceRegistry: namespace.NewEtcdRegistry(c.EtcdHelper),
|
|
||||||
minionRegistry: etcd.NewRegistry(c.EtcdHelper, nil),
|
|
||||||
limitRangeRegistry: limitrange.NewEtcdRegistry(c.EtcdHelper),
|
|
||||||
resourceQuotaRegistry: resourcequota.NewEtcdRegistry(c.EtcdHelper),
|
|
||||||
boundPodFactory: boundPodFactory,
|
|
||||||
client: c.Client,
|
client: c.Client,
|
||||||
portalNet: c.PortalNet,
|
portalNet: c.PortalNet,
|
||||||
rootWebService: new(restful.WebService),
|
rootWebService: new(restful.WebService),
|
||||||
@ -374,13 +365,28 @@ func logStackOnRecover(panicReason interface{}, httpWriter http.ResponseWriter)
|
|||||||
// init initializes master.
|
// init initializes master.
|
||||||
func (m *Master) init(c *Config) {
|
func (m *Master) init(c *Config) {
|
||||||
|
|
||||||
podStorage, bindingStorage := podetcd.NewREST(c.EtcdHelper, m.boundPodFactory)
|
boundPodFactory := &pod.BasicBoundPodFactory{}
|
||||||
|
podStorage, bindingStorage := podetcd.NewREST(c.EtcdHelper, boundPodFactory)
|
||||||
podRegistry := pod.NewRegistry(podStorage)
|
podRegistry := pod.NewRegistry(podStorage)
|
||||||
|
|
||||||
nodeRESTStorage := minion.NewREST(m.minionRegistry)
|
eventRegistry := event.NewEtcdRegistry(c.EtcdHelper, uint64(c.EventTTL.Seconds()))
|
||||||
|
limitRangeRegistry := limitrange.NewEtcdRegistry(c.EtcdHelper)
|
||||||
|
resourceQuotaRegistry := resourcequota.NewEtcdRegistry(c.EtcdHelper)
|
||||||
|
m.namespaceRegistry = namespace.NewEtcdRegistry(c.EtcdHelper)
|
||||||
|
|
||||||
|
// TODO: split me up into distinct storage registries
|
||||||
|
registry := etcd.NewRegistry(c.EtcdHelper, podRegistry)
|
||||||
|
|
||||||
|
m.serviceRegistry = registry
|
||||||
|
m.endpointRegistry = registry
|
||||||
|
m.nodeRegistry = registry
|
||||||
|
|
||||||
|
nodeStorage := minion.NewREST(m.nodeRegistry)
|
||||||
|
// TODO: unify the storage -> registry and storage -> client patterns
|
||||||
|
nodeStorageClient := RESTStorageToNodes(nodeStorage)
|
||||||
podCache := NewPodCache(
|
podCache := NewPodCache(
|
||||||
c.KubeletClient,
|
c.KubeletClient,
|
||||||
RESTStorageToNodes(nodeRESTStorage).Nodes(),
|
nodeStorageClient.Nodes(),
|
||||||
podRegistry,
|
podRegistry,
|
||||||
)
|
)
|
||||||
go util.Forever(func() { podCache.UpdateAllContainers() }, m.cacheTimeout)
|
go util.Forever(func() { podCache.UpdateAllContainers() }, m.cacheTimeout)
|
||||||
@ -394,16 +400,16 @@ func (m *Master) init(c *Config) {
|
|||||||
"pods": podStorage,
|
"pods": podStorage,
|
||||||
"bindings": bindingStorage,
|
"bindings": bindingStorage,
|
||||||
|
|
||||||
"replicationControllers": controller.NewREST(m.controllerRegistry, podRegistry),
|
"replicationControllers": controller.NewREST(registry, podRegistry),
|
||||||
"services": service.NewREST(m.serviceRegistry, c.Cloud, m.minionRegistry, m.portalNet),
|
"services": service.NewREST(m.serviceRegistry, c.Cloud, m.nodeRegistry, m.portalNet),
|
||||||
"endpoints": endpoint.NewREST(m.endpointRegistry),
|
"endpoints": endpoint.NewREST(m.endpointRegistry),
|
||||||
"minions": nodeRESTStorage,
|
"minions": nodeStorage,
|
||||||
"nodes": nodeRESTStorage,
|
"nodes": nodeStorage,
|
||||||
"events": event.NewREST(m.eventRegistry),
|
"events": event.NewREST(eventRegistry),
|
||||||
|
|
||||||
"limitRanges": limitrange.NewREST(m.limitRangeRegistry),
|
"limitRanges": limitrange.NewREST(limitRangeRegistry),
|
||||||
"resourceQuotas": resourcequota.NewREST(m.resourceQuotaRegistry),
|
"resourceQuotas": resourcequota.NewREST(resourceQuotaRegistry),
|
||||||
"resourceQuotaUsages": resourcequotausage.NewREST(m.resourceQuotaRegistry),
|
"resourceQuotaUsages": resourcequotausage.NewREST(resourceQuotaRegistry),
|
||||||
"namespaces": namespace.NewREST(m.namespaceRegistry),
|
"namespaces": namespace.NewREST(m.namespaceRegistry),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -542,7 +548,7 @@ func (m *Master) getServersToValidate(c *Config) map[string]apiserver.Server {
|
|||||||
}
|
}
|
||||||
serversToValidate[fmt.Sprintf("etcd-%d", ix)] = apiserver.Server{Addr: addr, Port: port, Path: "/v2/keys/"}
|
serversToValidate[fmt.Sprintf("etcd-%d", ix)] = apiserver.Server{Addr: addr, Port: port, Path: "/v2/keys/"}
|
||||||
}
|
}
|
||||||
nodes, err := m.minionRegistry.ListMinions(api.NewDefaultContext())
|
nodes, err := m.nodeRegistry.ListMinions(api.NewDefaultContext())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Failed to list minions: %v", err)
|
glog.Errorf("Failed to list minions: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ func TestGetServersToValidate(t *testing.T) {
|
|||||||
fakeClient.Machines = []string{"http://machine1:4001", "http://machine2", "http://machine3:4003"}
|
fakeClient.Machines = []string{"http://machine1:4001", "http://machine2", "http://machine3:4003"}
|
||||||
config.EtcdHelper = tools.EtcdHelper{fakeClient, latest.Codec, nil}
|
config.EtcdHelper = tools.EtcdHelper{fakeClient, latest.Codec, nil}
|
||||||
|
|
||||||
master.minionRegistry = registrytest.NewMinionRegistry([]string{"node1", "node2"}, api.NodeResources{})
|
master.nodeRegistry = registrytest.NewMinionRegistry([]string{"node1", "node2"}, api.NodeResources{})
|
||||||
|
|
||||||
servers := master.getServersToValidate(&config)
|
servers := master.getServersToValidate(&config)
|
||||||
|
|
||||||
|
@ -20,10 +20,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
|
||||||
etcderr "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors/etcd"
|
etcderr "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors/etcd"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/constraint"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||||
@ -34,8 +31,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// PodPath is the path to pod resources in etcd
|
|
||||||
PodPath string = "/registry/pods"
|
|
||||||
// ControllerPath is the path to controller resources in etcd
|
// ControllerPath is the path to controller resources in etcd
|
||||||
ControllerPath string = "/registry/controllers"
|
ControllerPath string = "/registry/controllers"
|
||||||
// ServicePath is the path to service resources in etcd
|
// ServicePath is the path to service resources in etcd
|
||||||
@ -53,15 +48,15 @@ const (
|
|||||||
// MinionRegistry, PodRegistry and ServiceRegistry, backed by etcd.
|
// MinionRegistry, PodRegistry and ServiceRegistry, backed by etcd.
|
||||||
type Registry struct {
|
type Registry struct {
|
||||||
tools.EtcdHelper
|
tools.EtcdHelper
|
||||||
boundPodFactory pod.BoundPodFactory
|
pods pod.Registry
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRegistry creates an etcd registry.
|
// NewRegistry creates an etcd registry.
|
||||||
func NewRegistry(helper tools.EtcdHelper, boundPodFactory pod.BoundPodFactory) *Registry {
|
func NewRegistry(helper tools.EtcdHelper, pods pod.Registry) *Registry {
|
||||||
registry := &Registry{
|
registry := &Registry{
|
||||||
EtcdHelper: helper,
|
EtcdHelper: helper,
|
||||||
|
pods: pods,
|
||||||
}
|
}
|
||||||
registry.boundPodFactory = boundPodFactory
|
|
||||||
return registry
|
return registry
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,239 +84,6 @@ func MakeEtcdItemKey(ctx api.Context, prefix string, id string) (string, error)
|
|||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// makePodListKey constructs etcd paths to pod directories enforcing namespace rules.
|
|
||||||
func makePodListKey(ctx api.Context) string {
|
|
||||||
return MakeEtcdListKey(ctx, PodPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// makePodKey constructs etcd paths to pod items enforcing namespace rules.
|
|
||||||
func makePodKey(ctx api.Context, id string) (string, error) {
|
|
||||||
return MakeEtcdItemKey(ctx, PodPath, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListPods obtains a list of pods with labels that match selector.
|
|
||||||
func (r *Registry) ListPods(ctx api.Context, selector labels.Selector) (*api.PodList, error) {
|
|
||||||
return r.ListPodsPredicate(ctx, func(pod *api.Pod) bool {
|
|
||||||
return selector.Matches(labels.Set(pod.Labels))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListPodsPredicate obtains a list of pods that match filter.
|
|
||||||
func (r *Registry) ListPodsPredicate(ctx api.Context, filter func(*api.Pod) bool) (*api.PodList, error) {
|
|
||||||
allPods := api.PodList{}
|
|
||||||
key := makePodListKey(ctx)
|
|
||||||
err := r.ExtractToList(key, &allPods)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
filtered := []api.Pod{}
|
|
||||||
for _, pod := range allPods.Items {
|
|
||||||
if filter(&pod) {
|
|
||||||
filtered = append(filtered, pod)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
allPods.Items = filtered
|
|
||||||
return &allPods, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// WatchPods begins watching for new, changed, or deleted pods.
|
|
||||||
func (r *Registry) WatchPods(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) {
|
|
||||||
version, err := tools.ParseWatchResourceVersion(resourceVersion, "pod")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
key := makePodListKey(ctx)
|
|
||||||
return r.WatchList(key, version, func(obj runtime.Object) bool {
|
|
||||||
podObj, ok := obj.(*api.Pod)
|
|
||||||
if !ok {
|
|
||||||
// Must be an error: return true to propagate to upper level.
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
fields := pod.PodToSelectableFields(podObj)
|
|
||||||
return label.Matches(labels.Set(podObj.Labels)) && field.Matches(fields)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPod gets a specific pod specified by its ID.
|
|
||||||
func (r *Registry) GetPod(ctx api.Context, id string) (*api.Pod, error) {
|
|
||||||
var pod api.Pod
|
|
||||||
key, err := makePodKey(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err = r.ExtractObj(key, &pod, false); err != nil {
|
|
||||||
return nil, etcderr.InterpretGetError(err, "pod", id)
|
|
||||||
}
|
|
||||||
return &pod, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeBoundPodsKey(machine string) string {
|
|
||||||
return "/registry/nodes/" + machine + "/boundpods"
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreatePod creates a pod based on a specification.
|
|
||||||
func (r *Registry) CreatePod(ctx api.Context, pod *api.Pod) error {
|
|
||||||
// Set current status to "Waiting".
|
|
||||||
pod.Status.Phase = api.PodPending
|
|
||||||
pod.Status.Host = ""
|
|
||||||
key, err := makePodKey(ctx, pod.Name)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = r.CreateObj(key, pod, 0)
|
|
||||||
return etcderr.InterpretCreateError(err, "pod", pod.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplyBinding implements binding's registry
|
|
||||||
func (r *Registry) ApplyBinding(ctx api.Context, binding *api.Binding) error {
|
|
||||||
return etcderr.InterpretCreateError(r.assignPod(ctx, binding.PodID, binding.Host), "binding", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// setPodHostTo sets the given pod's host to 'machine' iff it was previously 'oldMachine'.
|
|
||||||
// Returns the current state of the pod, or an error.
|
|
||||||
func (r *Registry) setPodHostTo(ctx api.Context, podID, oldMachine, machine string) (finalPod *api.Pod, err error) {
|
|
||||||
podKey, err := makePodKey(ctx, podID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = r.AtomicUpdate(podKey, &api.Pod{}, false, func(obj runtime.Object) (runtime.Object, error) {
|
|
||||||
pod, ok := obj.(*api.Pod)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected object: %#v", obj)
|
|
||||||
}
|
|
||||||
if pod.Status.Host != oldMachine {
|
|
||||||
return nil, fmt.Errorf("pod %v is already assigned to host %v", pod.Name, pod.Status.Host)
|
|
||||||
}
|
|
||||||
pod.Status.Host = machine
|
|
||||||
finalPod = pod
|
|
||||||
return pod, nil
|
|
||||||
})
|
|
||||||
return finalPod, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// assignPod assigns the given pod to the given machine.
|
|
||||||
func (r *Registry) assignPod(ctx api.Context, podID string, machine string) error {
|
|
||||||
finalPod, err := r.setPodHostTo(ctx, podID, "", machine)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
boundPod, err := r.boundPodFactory.MakeBoundPod(machine, finalPod)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Doing the constraint check this way provides atomicity guarantees.
|
|
||||||
contKey := makeBoundPodsKey(machine)
|
|
||||||
err = r.AtomicUpdate(contKey, &api.BoundPods{}, true, func(in runtime.Object) (runtime.Object, error) {
|
|
||||||
boundPodList := in.(*api.BoundPods)
|
|
||||||
boundPodList.Items = append(boundPodList.Items, *boundPod)
|
|
||||||
if errors := constraint.Allowed(boundPodList.Items); len(errors) > 0 {
|
|
||||||
return nil, fmt.Errorf("the assignment would cause the following constraints violation: %v", errors)
|
|
||||||
}
|
|
||||||
return boundPodList, nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
// Put the pod's host back the way it was. This is a terrible hack, but
|
|
||||||
// can't really be helped, since there's not really a way to do atomic
|
|
||||||
// multi-object changes in etcd.
|
|
||||||
if _, err2 := r.setPodHostTo(ctx, podID, machine, ""); err2 != nil {
|
|
||||||
glog.Errorf("Stranding pod %v; couldn't clear host after previous error: %v", podID, err2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Registry) UpdatePod(ctx api.Context, pod *api.Pod) error {
|
|
||||||
var podOut api.Pod
|
|
||||||
podKey, err := makePodKey(ctx, pod.Name)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = r.EtcdHelper.ExtractObj(podKey, &podOut, false)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
scheduled := podOut.Status.Host != ""
|
|
||||||
if scheduled {
|
|
||||||
pod.Status.Host = podOut.Status.Host
|
|
||||||
// If it's already been scheduled, limit the types of updates we'll accept.
|
|
||||||
errs := validation.ValidatePodUpdate(pod, &podOut)
|
|
||||||
if len(errs) != 0 {
|
|
||||||
return errors.NewInvalid("Pod", pod.Name, errs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// There's no race with the scheduler, because either this write will fail because the host
|
|
||||||
// has been updated, or the host update will fail because this pod has been updated.
|
|
||||||
err = r.EtcdHelper.SetObj(podKey, pod, 0 /* ttl */)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !scheduled {
|
|
||||||
// never scheduled, just update.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
containerKey := makeBoundPodsKey(podOut.Status.Host)
|
|
||||||
return r.AtomicUpdate(containerKey, &api.BoundPods{}, true, func(in runtime.Object) (runtime.Object, error) {
|
|
||||||
boundPods := in.(*api.BoundPods)
|
|
||||||
for ix := range boundPods.Items {
|
|
||||||
item := &boundPods.Items[ix]
|
|
||||||
if item.Name == pod.Name && item.Namespace == pod.Namespace {
|
|
||||||
item.Spec = pod.Spec
|
|
||||||
return boundPods, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// This really shouldn't happen
|
|
||||||
glog.Warningf("Couldn't find: %s in %#v", pod.Name, boundPods)
|
|
||||||
return boundPods, fmt.Errorf("failed to update pod, couldn't find %s in %#v", pod.Name, boundPods)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeletePod deletes an existing pod specified by its ID.
|
|
||||||
func (r *Registry) DeletePod(ctx api.Context, podID string) error {
|
|
||||||
var pod api.Pod
|
|
||||||
podKey, err := makePodKey(ctx, podID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = r.ExtractObj(podKey, &pod, false)
|
|
||||||
if err != nil {
|
|
||||||
return etcderr.InterpretDeleteError(err, "pod", podID)
|
|
||||||
}
|
|
||||||
// First delete the pod, so a scheduler doesn't notice it getting removed from the
|
|
||||||
// machine and attempt to put it somewhere.
|
|
||||||
err = r.Delete(podKey, true)
|
|
||||||
if err != nil {
|
|
||||||
return etcderr.InterpretDeleteError(err, "pod", podID)
|
|
||||||
}
|
|
||||||
machine := pod.Status.Host
|
|
||||||
if machine == "" {
|
|
||||||
// Pod was never scheduled anywhere, just return.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// Next, remove the pod from the machine atomically.
|
|
||||||
contKey := makeBoundPodsKey(machine)
|
|
||||||
return r.AtomicUpdate(contKey, &api.BoundPods{}, true, func(in runtime.Object) (runtime.Object, error) {
|
|
||||||
pods := in.(*api.BoundPods)
|
|
||||||
newPods := make([]api.BoundPod, 0, len(pods.Items))
|
|
||||||
found := false
|
|
||||||
for _, item := range pods.Items {
|
|
||||||
if item.Name != pod.Name || item.Namespace != pod.Namespace {
|
|
||||||
newPods = append(newPods, item)
|
|
||||||
} else {
|
|
||||||
found = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
// This really shouldn't happen, it indicates something is broken, and likely
|
|
||||||
// there is a lost pod somewhere.
|
|
||||||
// However it is "deleted" so log it and move on
|
|
||||||
glog.Warningf("Couldn't find: %s in %#v", podID, pods)
|
|
||||||
}
|
|
||||||
pods.Items = newPods
|
|
||||||
return pods, nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListControllers obtains a list of ReplicationControllers.
|
// ListControllers obtains a list of ReplicationControllers.
|
||||||
func (r *Registry) ListControllers(ctx api.Context) (*api.ReplicationControllerList, error) {
|
func (r *Registry) ListControllers(ctx api.Context) (*api.ReplicationControllerList, error) {
|
||||||
controllers := &api.ReplicationControllerList{}
|
controllers := &api.ReplicationControllerList{}
|
||||||
@ -348,7 +110,7 @@ func (r *Registry) WatchControllers(ctx api.Context, label, field labels.Selecto
|
|||||||
}
|
}
|
||||||
match := label.Matches(labels.Set(controller.Labels))
|
match := label.Matches(labels.Set(controller.Labels))
|
||||||
if match {
|
if match {
|
||||||
pods, err := r.ListPods(ctx, labels.Set(controller.Spec.Selector).AsSelector())
|
pods, err := r.pods.ListPods(ctx, labels.Set(controller.Spec.Selector).AsSelector())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Warningf("Error listing pods: %v", err)
|
glog.Warningf("Error listing pods: %v", err)
|
||||||
// No object that's useable so drop it on the floor
|
// No object that's useable so drop it on the floor
|
||||||
|
@ -18,7 +18,6 @@ package etcd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -26,7 +25,9 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
etcdgeneric "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic/etcd"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod"
|
||||||
|
podetcd "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod/etcd"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
||||||
|
|
||||||
@ -34,791 +35,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func NewTestEtcdRegistry(client tools.EtcdClient) *Registry {
|
func NewTestEtcdRegistry(client tools.EtcdClient) *Registry {
|
||||||
registry := NewRegistry(tools.EtcdHelper{client, latest.Codec, tools.RuntimeVersionAdapter{latest.ResourceVersioner}},
|
registry := NewRegistry(tools.EtcdHelper{client, latest.Codec, tools.RuntimeVersionAdapter{latest.ResourceVersioner}}, nil)
|
||||||
&pod.BasicBoundPodFactory{})
|
|
||||||
return registry
|
return registry
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestEtcdGetPodDifferentNamespace ensures same-name pods in different namespaces do not clash
|
func NewTestEtcdRegistryWithPods(client tools.EtcdClient) *Registry {
|
||||||
func TestEtcdGetPodDifferentNamespace(t *testing.T) {
|
helper := tools.EtcdHelper{client, latest.Codec, tools.RuntimeVersionAdapter{latest.ResourceVersioner}}
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
podStorage, _ := podetcd.NewREST(helper, nil)
|
||||||
|
registry := NewRegistry(helper, pod.NewRegistry(podStorage))
|
||||||
ctx1 := api.NewDefaultContext()
|
return registry
|
||||||
ctx2 := api.WithNamespace(api.NewContext(), "other")
|
|
||||||
|
|
||||||
key1, _ := makePodKey(ctx1, "foo")
|
|
||||||
key2, _ := makePodKey(ctx2, "foo")
|
|
||||||
|
|
||||||
fakeClient.Set(key1, runtime.EncodeOrDie(latest.Codec, &api.Pod{ObjectMeta: api.ObjectMeta{Namespace: "default", Name: "foo"}}), 0)
|
|
||||||
fakeClient.Set(key2, runtime.EncodeOrDie(latest.Codec, &api.Pod{ObjectMeta: api.ObjectMeta{Namespace: "other", Name: "foo"}}), 0)
|
|
||||||
|
|
||||||
registry := NewTestEtcdRegistry(fakeClient)
|
|
||||||
|
|
||||||
pod1, err := registry.GetPod(ctx1, "foo")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if pod1.Name != "foo" {
|
|
||||||
t.Errorf("Unexpected pod: %#v", pod1)
|
|
||||||
}
|
|
||||||
if pod1.Namespace != "default" {
|
|
||||||
t.Errorf("Unexpected pod: %#v", pod1)
|
|
||||||
}
|
|
||||||
|
|
||||||
pod2, err := registry.GetPod(ctx2, "foo")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if pod2.Name != "foo" {
|
|
||||||
t.Errorf("Unexpected pod: %#v", pod2)
|
|
||||||
}
|
|
||||||
if pod2.Namespace != "other" {
|
|
||||||
t.Errorf("Unexpected pod: %#v", pod2)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEtcdGetPod(t *testing.T) {
|
|
||||||
ctx := api.NewDefaultContext()
|
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
|
||||||
key, _ := makePodKey(ctx, "foo")
|
|
||||||
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}}), 0)
|
|
||||||
registry := NewTestEtcdRegistry(fakeClient)
|
|
||||||
pod, err := registry.GetPod(ctx, "foo")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if pod.Name != "foo" {
|
|
||||||
t.Errorf("Unexpected pod: %#v", pod)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEtcdGetPodNotFound(t *testing.T) {
|
|
||||||
ctx := api.NewDefaultContext()
|
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
|
||||||
key, _ := makePodKey(ctx, "foo")
|
|
||||||
fakeClient.Data[key] = tools.EtcdResponseWithError{
|
|
||||||
R: &etcd.Response{
|
|
||||||
Node: nil,
|
|
||||||
},
|
|
||||||
E: tools.EtcdErrorNotFound,
|
|
||||||
}
|
|
||||||
registry := NewTestEtcdRegistry(fakeClient)
|
|
||||||
_, err := registry.GetPod(ctx, "foo")
|
|
||||||
if !errors.IsNotFound(err) {
|
|
||||||
t.Errorf("Unexpected error returned: %#v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEtcdCreatePod(t *testing.T) {
|
|
||||||
ctx := api.NewDefaultContext()
|
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
|
||||||
fakeClient.TestIndex = true
|
|
||||||
key, _ := makePodKey(ctx, "foo")
|
|
||||||
fakeClient.Data[key] = tools.EtcdResponseWithError{
|
|
||||||
R: &etcd.Response{
|
|
||||||
Node: nil,
|
|
||||||
},
|
|
||||||
E: tools.EtcdErrorNotFound,
|
|
||||||
}
|
|
||||||
fakeClient.Set("/registry/nodes/machine/boundpods", runtime.EncodeOrDie(latest.Codec, &api.BoundPods{}), 0)
|
|
||||||
registry := NewTestEtcdRegistry(fakeClient)
|
|
||||||
err := registry.CreatePod(ctx, &api.Pod{
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Name: "foo",
|
|
||||||
Namespace: api.NamespaceDefault,
|
|
||||||
},
|
|
||||||
Spec: api.PodSpec{
|
|
||||||
Containers: []api.Container{
|
|
||||||
{
|
|
||||||
Name: "foo",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Suddenly, a wild scheduler appears:
|
|
||||||
err = registry.ApplyBinding(ctx, &api.Binding{PodID: "foo", Host: "machine", ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault}})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := fakeClient.Get(key, false, false)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error %v", err)
|
|
||||||
}
|
|
||||||
var pod api.Pod
|
|
||||||
err = latest.Codec.DecodeInto([]byte(resp.Node.Value), &pod)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if pod.Name != "foo" {
|
|
||||||
t.Errorf("Unexpected pod: %#v %s", pod, resp.Node.Value)
|
|
||||||
}
|
|
||||||
var boundPods api.BoundPods
|
|
||||||
resp, err = fakeClient.Get("/registry/nodes/machine/boundpods", false, false)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = latest.Codec.DecodeInto([]byte(resp.Node.Value), &boundPods)
|
|
||||||
if len(boundPods.Items) != 1 || boundPods.Items[0].Name != "foo" {
|
|
||||||
t.Errorf("Unexpected boundPod list: %#v", boundPods)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEtcdCreatePodFailsWithoutNamespace(t *testing.T) {
|
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
|
||||||
fakeClient.TestIndex = true
|
|
||||||
registry := NewTestEtcdRegistry(fakeClient)
|
|
||||||
err := registry.CreatePod(api.NewContext(), &api.Pod{
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Name: "foo",
|
|
||||||
},
|
|
||||||
Spec: api.PodSpec{
|
|
||||||
Containers: []api.Container{
|
|
||||||
{
|
|
||||||
Name: "foo",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
// Accept "namespace" or "Namespace".
|
|
||||||
if err == nil || !strings.Contains(err.Error(), "amespace") {
|
|
||||||
t.Fatalf("expected error that namespace was missing from context, got: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEtcdCreatePodAlreadyExisting(t *testing.T) {
|
|
||||||
ctx := api.NewDefaultContext()
|
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
|
||||||
key, _ := makePodKey(ctx, "foo")
|
|
||||||
fakeClient.Data[key] = tools.EtcdResponseWithError{
|
|
||||||
R: &etcd.Response{
|
|
||||||
Node: &etcd.Node{
|
|
||||||
Value: runtime.EncodeOrDie(latest.Codec, &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
E: nil,
|
|
||||||
}
|
|
||||||
registry := NewTestEtcdRegistry(fakeClient)
|
|
||||||
err := registry.CreatePod(ctx, &api.Pod{
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Name: "foo",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if !errors.IsAlreadyExists(err) {
|
|
||||||
t.Errorf("Unexpected error returned: %#v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEtcdCreatePodWithContainersError(t *testing.T) {
|
|
||||||
ctx := api.NewDefaultContext()
|
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
|
||||||
fakeClient.TestIndex = true
|
|
||||||
key, _ := makePodKey(ctx, "foo")
|
|
||||||
fakeClient.Data[key] = tools.EtcdResponseWithError{
|
|
||||||
R: &etcd.Response{
|
|
||||||
Node: nil,
|
|
||||||
},
|
|
||||||
E: tools.EtcdErrorNotFound,
|
|
||||||
}
|
|
||||||
fakeClient.Data["/registry/nodes/machine/boundpods"] = tools.EtcdResponseWithError{
|
|
||||||
R: &etcd.Response{
|
|
||||||
Node: nil,
|
|
||||||
},
|
|
||||||
E: tools.EtcdErrorNodeExist, // validate that ApplyBinding is translating Create errors
|
|
||||||
}
|
|
||||||
registry := NewTestEtcdRegistry(fakeClient)
|
|
||||||
err := registry.CreatePod(ctx, &api.Pod{
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Name: "foo",
|
|
||||||
Namespace: api.NamespaceDefault,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Suddenly, a wild scheduler appears:
|
|
||||||
err = registry.ApplyBinding(ctx, &api.Binding{PodID: "foo", Host: "machine"})
|
|
||||||
if !errors.IsAlreadyExists(err) {
|
|
||||||
t.Fatalf("Unexpected error returned: %#v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
existingPod, err := registry.GetPod(ctx, "foo")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if existingPod.Status.Host == "machine" {
|
|
||||||
t.Fatal("Pod's host changed in response to an non-apply-able binding.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEtcdCreatePodWithContainersNotFound(t *testing.T) {
|
|
||||||
ctx := api.NewDefaultContext()
|
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
|
||||||
fakeClient.TestIndex = true
|
|
||||||
key, _ := makePodKey(ctx, "foo")
|
|
||||||
fakeClient.Data[key] = tools.EtcdResponseWithError{
|
|
||||||
R: &etcd.Response{
|
|
||||||
Node: nil,
|
|
||||||
},
|
|
||||||
E: tools.EtcdErrorNotFound,
|
|
||||||
}
|
|
||||||
fakeClient.Data["/registry/nodes/machine/boundpods"] = tools.EtcdResponseWithError{
|
|
||||||
R: &etcd.Response{
|
|
||||||
Node: nil,
|
|
||||||
},
|
|
||||||
E: tools.EtcdErrorNotFound,
|
|
||||||
}
|
|
||||||
registry := NewTestEtcdRegistry(fakeClient)
|
|
||||||
err := registry.CreatePod(ctx, &api.Pod{
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Name: "foo",
|
|
||||||
Namespace: api.NamespaceDefault,
|
|
||||||
},
|
|
||||||
Spec: api.PodSpec{
|
|
||||||
Containers: []api.Container{
|
|
||||||
{
|
|
||||||
Name: "foo",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Suddenly, a wild scheduler appears:
|
|
||||||
err = registry.ApplyBinding(ctx, &api.Binding{PodID: "foo", Host: "machine"})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := fakeClient.Get(key, false, false)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error %v", err)
|
|
||||||
}
|
|
||||||
var pod api.Pod
|
|
||||||
err = latest.Codec.DecodeInto([]byte(resp.Node.Value), &pod)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if pod.Name != "foo" {
|
|
||||||
t.Errorf("Unexpected pod: %#v %s", pod, resp.Node.Value)
|
|
||||||
}
|
|
||||||
var boundPods api.BoundPods
|
|
||||||
resp, err = fakeClient.Get("/registry/nodes/machine/boundpods", false, false)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = latest.Codec.DecodeInto([]byte(resp.Node.Value), &boundPods)
|
|
||||||
if len(boundPods.Items) != 1 || boundPods.Items[0].Name != "foo" {
|
|
||||||
t.Errorf("Unexpected boundPod list: %#v", boundPods)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEtcdCreatePodWithExistingContainers(t *testing.T) {
|
|
||||||
ctx := api.NewDefaultContext()
|
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
|
||||||
fakeClient.TestIndex = true
|
|
||||||
key, _ := makePodKey(ctx, "foo")
|
|
||||||
fakeClient.Data[key] = tools.EtcdResponseWithError{
|
|
||||||
R: &etcd.Response{
|
|
||||||
Node: nil,
|
|
||||||
},
|
|
||||||
E: tools.EtcdErrorNotFound,
|
|
||||||
}
|
|
||||||
fakeClient.Set("/registry/nodes/machine/boundpods", runtime.EncodeOrDie(latest.Codec, &api.BoundPods{
|
|
||||||
Items: []api.BoundPod{
|
|
||||||
{ObjectMeta: api.ObjectMeta{Name: "bar"}},
|
|
||||||
},
|
|
||||||
}), 0)
|
|
||||||
registry := NewTestEtcdRegistry(fakeClient)
|
|
||||||
err := registry.CreatePod(ctx, &api.Pod{
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Name: "foo",
|
|
||||||
Namespace: api.NamespaceDefault,
|
|
||||||
},
|
|
||||||
Spec: api.PodSpec{
|
|
||||||
Containers: []api.Container{
|
|
||||||
{
|
|
||||||
Name: "foo",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Suddenly, a wild scheduler appears:
|
|
||||||
err = registry.ApplyBinding(ctx, &api.Binding{PodID: "foo", Host: "machine"})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := fakeClient.Get(key, false, false)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error %v", err)
|
|
||||||
}
|
|
||||||
var pod api.Pod
|
|
||||||
err = latest.Codec.DecodeInto([]byte(resp.Node.Value), &pod)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if pod.Name != "foo" {
|
|
||||||
t.Errorf("Unexpected pod: %#v %s", pod, resp.Node.Value)
|
|
||||||
}
|
|
||||||
var boundPods api.BoundPods
|
|
||||||
resp, err = fakeClient.Get("/registry/nodes/machine/boundpods", false, false)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = latest.Codec.DecodeInto([]byte(resp.Node.Value), &boundPods)
|
|
||||||
if len(boundPods.Items) != 2 || boundPods.Items[1].Name != "foo" {
|
|
||||||
t.Errorf("Unexpected boundPod list: %#v", boundPods)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEtcdUpdatePodNotFound(t *testing.T) {
|
|
||||||
ctx := api.NewDefaultContext()
|
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
|
||||||
fakeClient.TestIndex = true
|
|
||||||
|
|
||||||
key, _ := makePodKey(ctx, "foo")
|
|
||||||
fakeClient.Data[key] = tools.EtcdResponseWithError{
|
|
||||||
R: &etcd.Response{},
|
|
||||||
E: tools.EtcdErrorNotFound,
|
|
||||||
}
|
|
||||||
|
|
||||||
registry := NewTestEtcdRegistry(fakeClient)
|
|
||||||
podIn := api.Pod{
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Name: "foo",
|
|
||||||
ResourceVersion: "1",
|
|
||||||
Labels: map[string]string{
|
|
||||||
"foo": "bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
err := registry.UpdatePod(ctx, &podIn)
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("unexpected non-error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEtcdUpdatePodNotScheduled(t *testing.T) {
|
|
||||||
ctx := api.NewDefaultContext()
|
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
|
||||||
fakeClient.TestIndex = true
|
|
||||||
|
|
||||||
key, _ := makePodKey(ctx, "foo")
|
|
||||||
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, &api.Pod{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
|
||||||
}), 1)
|
|
||||||
|
|
||||||
registry := NewTestEtcdRegistry(fakeClient)
|
|
||||||
podIn := api.Pod{
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Name: "foo",
|
|
||||||
ResourceVersion: "1",
|
|
||||||
Labels: map[string]string{
|
|
||||||
"foo": "bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Spec: api.PodSpec{
|
|
||||||
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
err := registry.UpdatePod(ctx, &podIn)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
response, err := fakeClient.Get(key, false, false)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
var podOut api.Pod
|
|
||||||
latest.Codec.DecodeInto([]byte(response.Node.Value), &podOut)
|
|
||||||
if !api.Semantic.DeepEqual(podOut, podIn) {
|
|
||||||
t.Errorf("expected: %v, got: %v", podOut, podIn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEtcdUpdatePodScheduled(t *testing.T) {
|
|
||||||
ctx := api.NewDefaultContext()
|
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
|
||||||
fakeClient.TestIndex = true
|
|
||||||
|
|
||||||
key, _ := makePodKey(ctx, "foo")
|
|
||||||
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, &api.Pod{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.PodSpec{
|
|
||||||
// Host: "machine",
|
|
||||||
Containers: []api.Container{
|
|
||||||
{
|
|
||||||
Image: "foo:v1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Status: api.PodStatus{
|
|
||||||
Host: "machine",
|
|
||||||
},
|
|
||||||
}), 1)
|
|
||||||
|
|
||||||
contKey := "/registry/nodes/machine/boundpods"
|
|
||||||
fakeClient.Set(contKey, runtime.EncodeOrDie(latest.Codec, &api.BoundPods{
|
|
||||||
Items: []api.BoundPod{
|
|
||||||
{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "other"},
|
|
||||||
Spec: api.PodSpec{
|
|
||||||
Containers: []api.Container{
|
|
||||||
{
|
|
||||||
Image: "foo:v1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.PodSpec{
|
|
||||||
Containers: []api.Container{
|
|
||||||
{
|
|
||||||
Image: "foo:v1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}), 0)
|
|
||||||
|
|
||||||
registry := NewTestEtcdRegistry(fakeClient)
|
|
||||||
podIn := api.Pod{
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Name: "foo",
|
|
||||||
Namespace: api.NamespaceDefault,
|
|
||||||
ResourceVersion: "1",
|
|
||||||
Labels: map[string]string{
|
|
||||||
"foo": "bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Spec: api.PodSpec{
|
|
||||||
Containers: []api.Container{
|
|
||||||
{
|
|
||||||
Image: "foo:v2",
|
|
||||||
ImagePullPolicy: api.PullIfNotPresent,
|
|
||||||
TerminationMessagePath: api.TerminationMessagePathDefault,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
|
||||||
},
|
|
||||||
Status: api.PodStatus{
|
|
||||||
Host: "machine",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
err := registry.UpdatePod(ctx, &podIn)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
response, err := fakeClient.Get(key, false, false)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
var podOut api.Pod
|
|
||||||
latest.Codec.DecodeInto([]byte(response.Node.Value), &podOut)
|
|
||||||
if !api.Semantic.DeepEqual(podOut, podIn) {
|
|
||||||
t.Errorf("expected: %#v, got: %#v", podOut, podIn)
|
|
||||||
}
|
|
||||||
|
|
||||||
response, err = fakeClient.Get(contKey, false, false)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
var list api.BoundPods
|
|
||||||
if err := latest.Codec.DecodeInto([]byte(response.Node.Value), &list); err != nil {
|
|
||||||
t.Fatalf("unexpected error decoding response: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(list.Items) != 2 || !api.Semantic.DeepEqual(list.Items[1].Spec, podIn.Spec) {
|
|
||||||
t.Errorf("unexpected container list: %d\n items[0] - %#v\n podin.spec - %#v\n", len(list.Items), list.Items[1].Spec, podIn.Spec)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEtcdDeletePod(t *testing.T) {
|
|
||||||
ctx := api.NewDefaultContext()
|
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
|
||||||
fakeClient.TestIndex = true
|
|
||||||
|
|
||||||
key, _ := makePodKey(ctx, "foo")
|
|
||||||
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, &api.Pod{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault},
|
|
||||||
Status: api.PodStatus{Host: "machine"},
|
|
||||||
}), 0)
|
|
||||||
fakeClient.Set("/registry/nodes/machine/boundpods", runtime.EncodeOrDie(latest.Codec, &api.BoundPods{
|
|
||||||
Items: []api.BoundPod{
|
|
||||||
{ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault}},
|
|
||||||
},
|
|
||||||
}), 0)
|
|
||||||
registry := NewTestEtcdRegistry(fakeClient)
|
|
||||||
err := registry.DeletePod(ctx, "foo")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(fakeClient.DeletedKeys) != 1 {
|
|
||||||
t.Errorf("Expected 1 delete, found %#v", fakeClient.DeletedKeys)
|
|
||||||
} else if fakeClient.DeletedKeys[0] != key {
|
|
||||||
t.Errorf("Unexpected key: %s, expected %s", fakeClient.DeletedKeys[0], key)
|
|
||||||
}
|
|
||||||
response, err := fakeClient.Get("/registry/nodes/machine/boundpods", false, false)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error %v", err)
|
|
||||||
}
|
|
||||||
var boundPods api.BoundPods
|
|
||||||
latest.Codec.DecodeInto([]byte(response.Node.Value), &boundPods)
|
|
||||||
if len(boundPods.Items) != 0 {
|
|
||||||
t.Errorf("Unexpected container set: %s, expected empty", response.Node.Value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEtcdDeletePodMultipleContainers(t *testing.T) {
|
|
||||||
ctx := api.NewDefaultContext()
|
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
|
||||||
fakeClient.TestIndex = true
|
|
||||||
key, _ := makePodKey(ctx, "foo")
|
|
||||||
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, &api.Pod{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault},
|
|
||||||
Status: api.PodStatus{Host: "machine"},
|
|
||||||
}), 0)
|
|
||||||
fakeClient.Set("/registry/nodes/machine/boundpods", runtime.EncodeOrDie(latest.Codec, &api.BoundPods{
|
|
||||||
Items: []api.BoundPod{
|
|
||||||
{ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "other"}},
|
|
||||||
{ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault}},
|
|
||||||
},
|
|
||||||
}), 0)
|
|
||||||
registry := NewTestEtcdRegistry(fakeClient)
|
|
||||||
err := registry.DeletePod(ctx, "foo")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(fakeClient.DeletedKeys) != 1 {
|
|
||||||
t.Errorf("Expected 1 delete, found %#v", fakeClient.DeletedKeys)
|
|
||||||
}
|
|
||||||
if fakeClient.DeletedKeys[0] != key {
|
|
||||||
t.Errorf("Unexpected key: %s, expected %s", fakeClient.DeletedKeys[0], key)
|
|
||||||
}
|
|
||||||
response, err := fakeClient.Get("/registry/nodes/machine/boundpods", false, false)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error %v", err)
|
|
||||||
}
|
|
||||||
var boundPods api.BoundPods
|
|
||||||
latest.Codec.DecodeInto([]byte(response.Node.Value), &boundPods)
|
|
||||||
if len(boundPods.Items) != 1 {
|
|
||||||
t.Fatalf("Unexpected boundPod set: %#v, expected empty", boundPods)
|
|
||||||
}
|
|
||||||
if boundPods.Items[0].Namespace != "other" {
|
|
||||||
t.Errorf("Deleted wrong boundPod: %#v", boundPods)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEtcdEmptyListPods(t *testing.T) {
|
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
|
||||||
ctx := api.NewDefaultContext()
|
|
||||||
key := makePodListKey(ctx)
|
|
||||||
fakeClient.Data[key] = tools.EtcdResponseWithError{
|
|
||||||
R: &etcd.Response{
|
|
||||||
Node: &etcd.Node{
|
|
||||||
Nodes: []*etcd.Node{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
E: nil,
|
|
||||||
}
|
|
||||||
registry := NewTestEtcdRegistry(fakeClient)
|
|
||||||
pods, err := registry.ListPods(ctx, labels.Everything())
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if len(pods.Items) != 0 {
|
|
||||||
t.Errorf("Unexpected pod list: %#v", pods)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEtcdListPodsNotFound(t *testing.T) {
|
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
|
||||||
ctx := api.NewDefaultContext()
|
|
||||||
key := makePodListKey(ctx)
|
|
||||||
fakeClient.Data[key] = tools.EtcdResponseWithError{
|
|
||||||
R: &etcd.Response{},
|
|
||||||
E: tools.EtcdErrorNotFound,
|
|
||||||
}
|
|
||||||
registry := NewTestEtcdRegistry(fakeClient)
|
|
||||||
pods, err := registry.ListPods(ctx, labels.Everything())
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(pods.Items) != 0 {
|
|
||||||
t.Errorf("Unexpected pod list: %#v", pods)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEtcdListPods(t *testing.T) {
|
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
|
||||||
ctx := api.NewDefaultContext()
|
|
||||||
key := makePodListKey(ctx)
|
|
||||||
fakeClient.Data[key] = tools.EtcdResponseWithError{
|
|
||||||
R: &etcd.Response{
|
|
||||||
Node: &etcd.Node{
|
|
||||||
Nodes: []*etcd.Node{
|
|
||||||
{
|
|
||||||
Value: runtime.EncodeOrDie(latest.Codec, &api.Pod{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
|
||||||
Status: api.PodStatus{Host: "machine"},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Value: runtime.EncodeOrDie(latest.Codec, &api.Pod{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "bar"},
|
|
||||||
Status: api.PodStatus{Host: "machine"},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
E: nil,
|
|
||||||
}
|
|
||||||
registry := NewTestEtcdRegistry(fakeClient)
|
|
||||||
pods, err := registry.ListPods(ctx, labels.Everything())
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(pods.Items) != 2 || pods.Items[0].Name != "foo" || pods.Items[1].Name != "bar" {
|
|
||||||
t.Errorf("Unexpected pod list: %#v", pods)
|
|
||||||
}
|
|
||||||
if pods.Items[0].Status.Host != "machine" ||
|
|
||||||
pods.Items[1].Status.Host != "machine" {
|
|
||||||
t.Errorf("Failed to populate host name.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEtcdWatchPods(t *testing.T) {
|
|
||||||
ctx := api.NewDefaultContext()
|
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
|
||||||
registry := NewTestEtcdRegistry(fakeClient)
|
|
||||||
watching, err := registry.WatchPods(ctx,
|
|
||||||
labels.Everything(),
|
|
||||||
labels.Everything(),
|
|
||||||
"1",
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
fakeClient.WaitForWatchCompletion()
|
|
||||||
|
|
||||||
select {
|
|
||||||
case _, ok := <-watching.ResultChan():
|
|
||||||
if !ok {
|
|
||||||
t.Errorf("watching channel should be open")
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
fakeClient.WatchInjectError <- nil
|
|
||||||
if _, ok := <-watching.ResultChan(); ok {
|
|
||||||
t.Errorf("watching channel should be closed")
|
|
||||||
}
|
|
||||||
watching.Stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEtcdWatchPodsMatch(t *testing.T) {
|
|
||||||
ctx := api.NewDefaultContext()
|
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
|
||||||
registry := NewTestEtcdRegistry(fakeClient)
|
|
||||||
watching, err := registry.WatchPods(ctx,
|
|
||||||
labels.SelectorFromSet(labels.Set{"name": "foo"}),
|
|
||||||
labels.Everything(),
|
|
||||||
"1",
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
fakeClient.WaitForWatchCompletion()
|
|
||||||
|
|
||||||
pod := &api.Pod{
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Name: "foo",
|
|
||||||
Labels: map[string]string{
|
|
||||||
"name": "foo",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
podBytes, _ := latest.Codec.Encode(pod)
|
|
||||||
fakeClient.WatchResponse <- &etcd.Response{
|
|
||||||
Action: "create",
|
|
||||||
Node: &etcd.Node{
|
|
||||||
Value: string(podBytes),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
case _, ok := <-watching.ResultChan():
|
|
||||||
if !ok {
|
|
||||||
t.Errorf("watching channel should be open")
|
|
||||||
}
|
|
||||||
case <-time.After(time.Millisecond * 100):
|
|
||||||
t.Error("unexpected timeout from result channel")
|
|
||||||
}
|
|
||||||
watching.Stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEtcdWatchPodsNotMatch(t *testing.T) {
|
|
||||||
ctx := api.NewDefaultContext()
|
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
|
||||||
registry := NewTestEtcdRegistry(fakeClient)
|
|
||||||
watching, err := registry.WatchPods(ctx,
|
|
||||||
labels.SelectorFromSet(labels.Set{"name": "foo"}),
|
|
||||||
labels.Everything(),
|
|
||||||
"1",
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
fakeClient.WaitForWatchCompletion()
|
|
||||||
|
|
||||||
pod := &api.Pod{
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Name: "bar",
|
|
||||||
Labels: map[string]string{
|
|
||||||
"name": "bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
podBytes, _ := latest.Codec.Encode(pod)
|
|
||||||
fakeClient.WatchResponse <- &etcd.Response{
|
|
||||||
Action: "create",
|
|
||||||
Node: &etcd.Node{
|
|
||||||
Value: string(podBytes),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-watching.ResultChan():
|
|
||||||
t.Error("unexpected result from result channel")
|
|
||||||
case <-time.After(time.Millisecond * 100):
|
|
||||||
// expected case
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEtcdListControllersNotFound(t *testing.T) {
|
func TestEtcdListControllersNotFound(t *testing.T) {
|
||||||
@ -1081,8 +306,8 @@ func TestEtcdWatchController(t *testing.T) {
|
|||||||
func TestEtcdWatchControllersMatch(t *testing.T) {
|
func TestEtcdWatchControllersMatch(t *testing.T) {
|
||||||
ctx := api.NewDefaultContext()
|
ctx := api.NewDefaultContext()
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
fakeClient := tools.NewFakeEtcdClient(t)
|
||||||
fakeClient.ExpectNotFoundGet(makePodListKey(ctx))
|
fakeClient.ExpectNotFoundGet(etcdgeneric.NamespaceKeyRootFunc(ctx, "/registry/pods"))
|
||||||
registry := NewTestEtcdRegistry(fakeClient)
|
registry := NewTestEtcdRegistryWithPods(fakeClient)
|
||||||
watching, err := registry.WatchControllers(ctx,
|
watching, err := registry.WatchControllers(ctx,
|
||||||
labels.SelectorFromSet(labels.Set{"name": "foo"}),
|
labels.SelectorFromSet(labels.Set{"name": "foo"}),
|
||||||
labels.Everything(),
|
labels.Everything(),
|
||||||
@ -1122,8 +347,8 @@ func TestEtcdWatchControllersMatch(t *testing.T) {
|
|||||||
func TestEtcdWatchControllersNotMatch(t *testing.T) {
|
func TestEtcdWatchControllersNotMatch(t *testing.T) {
|
||||||
ctx := api.NewDefaultContext()
|
ctx := api.NewDefaultContext()
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
fakeClient := tools.NewFakeEtcdClient(t)
|
||||||
fakeClient.ExpectNotFoundGet(makePodListKey(ctx))
|
fakeClient.ExpectNotFoundGet(etcdgeneric.NamespaceKeyRootFunc(ctx, "/registry/pods"))
|
||||||
registry := NewTestEtcdRegistry(fakeClient)
|
registry := NewTestEtcdRegistryWithPods(fakeClient)
|
||||||
watching, err := registry.WatchControllers(ctx,
|
watching, err := registry.WatchControllers(ctx,
|
||||||
labels.SelectorFromSet(labels.Set{"name": "foo"}),
|
labels.SelectorFromSet(labels.Set{"name": "foo"}),
|
||||||
labels.Everything(),
|
labels.Everything(),
|
||||||
|
@ -30,7 +30,6 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
@ -68,7 +67,7 @@ func newHelper(t *testing.T) (*tools.FakeEtcdClient, tools.EtcdHelper) {
|
|||||||
|
|
||||||
func newStorage(t *testing.T) (*REST, *BindingREST, *tools.FakeEtcdClient, tools.EtcdHelper) {
|
func newStorage(t *testing.T) (*REST, *BindingREST, *tools.FakeEtcdClient, tools.EtcdHelper) {
|
||||||
fakeEtcdClient, h := newHelper(t)
|
fakeEtcdClient, h := newHelper(t)
|
||||||
storage, bindingStorage := NewREST(h, &pod.BasicBoundPodFactory{ServiceRegistry: ®istrytest.ServiceRegistry{}})
|
storage, bindingStorage := NewREST(h, &pod.BasicBoundPodFactory{})
|
||||||
storage = storage.WithPodStatus(&fakeCache{statusToReturn: &api.PodStatus{}})
|
storage = storage.WithPodStatus(&fakeCache{statusToReturn: &api.PodStatus{}})
|
||||||
return storage, bindingStorage, fakeEtcdClient, h
|
return storage, bindingStorage, fakeEtcdClient, h
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,8 @@ type Registry interface {
|
|||||||
DeletePod(ctx api.Context, podID string) error
|
DeletePod(ctx api.Context, podID string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Storage is an interface for a standard REST Storage backend
|
||||||
|
// TODO: move me somewhere common
|
||||||
type Storage interface {
|
type Storage interface {
|
||||||
apiserver.RESTDeleter
|
apiserver.RESTDeleter
|
||||||
apiserver.RESTLister
|
apiserver.RESTLister
|
||||||
@ -50,10 +52,13 @@ type Storage interface {
|
|||||||
Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error)
|
Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// storage puts strong typing around storage calls
|
||||||
type storage struct {
|
type storage struct {
|
||||||
Storage
|
Storage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewRegistry returns a new Registry interface for the given Storage. Any mismatched
|
||||||
|
// types will panic.
|
||||||
func NewRegistry(s Storage) Registry {
|
func NewRegistry(s Storage) Registry {
|
||||||
return &storage{s}
|
return &storage{s}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user