Merge pull request #848 from kelseyhightower/breakup-registry-package
Breakup the registry package into separate packages.
This commit is contained in:
@@ -25,10 +25,17 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/controller"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/endpoint"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/etcd"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/memory"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/minion"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/service"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/scheduler"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/scheduler"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
"github.com/coreos/go-etcd/etcd"
|
|
||||||
|
goetcd "github.com/coreos/go-etcd/etcd"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -46,10 +53,10 @@ 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 {
|
||||||
podRegistry registry.PodRegistry
|
podRegistry pod.Registry
|
||||||
controllerRegistry registry.ControllerRegistry
|
controllerRegistry controller.Registry
|
||||||
serviceRegistry registry.ServiceRegistry
|
serviceRegistry service.Registry
|
||||||
minionRegistry registry.MinionRegistry
|
minionRegistry minion.Registry
|
||||||
storage map[string]apiserver.RESTStorage
|
storage map[string]apiserver.RESTStorage
|
||||||
client *client.Client
|
client *client.Client
|
||||||
}
|
}
|
||||||
@@ -57,10 +64,10 @@ type Master struct {
|
|||||||
// NewMemoryServer returns a new instance of Master backed with memory (not etcd).
|
// NewMemoryServer returns a new instance of Master backed with memory (not etcd).
|
||||||
func NewMemoryServer(c *Config) *Master {
|
func NewMemoryServer(c *Config) *Master {
|
||||||
m := &Master{
|
m := &Master{
|
||||||
podRegistry: registry.MakeMemoryRegistry(),
|
podRegistry: memory.NewRegistry(),
|
||||||
controllerRegistry: registry.MakeMemoryRegistry(),
|
controllerRegistry: memory.NewRegistry(),
|
||||||
serviceRegistry: registry.MakeMemoryRegistry(),
|
serviceRegistry: memory.NewRegistry(),
|
||||||
minionRegistry: registry.MakeMinionRegistry(c.Minions),
|
minionRegistry: minion.NewRegistry(c.Minions),
|
||||||
client: c.Client,
|
client: c.Client,
|
||||||
}
|
}
|
||||||
m.init(c.Cloud, c.PodInfoGetter)
|
m.init(c.Cloud, c.PodInfoGetter)
|
||||||
@@ -69,12 +76,12 @@ func NewMemoryServer(c *Config) *Master {
|
|||||||
|
|
||||||
// New returns a new instance of Master connected to the given etcdServer.
|
// New returns a new instance of Master connected to the given etcdServer.
|
||||||
func New(c *Config) *Master {
|
func New(c *Config) *Master {
|
||||||
etcdClient := etcd.NewClient(c.EtcdServers)
|
etcdClient := goetcd.NewClient(c.EtcdServers)
|
||||||
minionRegistry := minionRegistryMaker(c)
|
minionRegistry := minionRegistryMaker(c)
|
||||||
m := &Master{
|
m := &Master{
|
||||||
podRegistry: registry.MakeEtcdRegistry(etcdClient, minionRegistry),
|
podRegistry: etcd.NewRegistry(etcdClient, minionRegistry),
|
||||||
controllerRegistry: registry.MakeEtcdRegistry(etcdClient, minionRegistry),
|
controllerRegistry: etcd.NewRegistry(etcdClient, minionRegistry),
|
||||||
serviceRegistry: registry.MakeEtcdRegistry(etcdClient, minionRegistry),
|
serviceRegistry: etcd.NewRegistry(etcdClient, minionRegistry),
|
||||||
minionRegistry: minionRegistry,
|
minionRegistry: minionRegistry,
|
||||||
client: c.Client,
|
client: c.Client,
|
||||||
}
|
}
|
||||||
@@ -82,23 +89,23 @@ func New(c *Config) *Master {
|
|||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func minionRegistryMaker(c *Config) registry.MinionRegistry {
|
func minionRegistryMaker(c *Config) minion.Registry {
|
||||||
var minionRegistry registry.MinionRegistry
|
var minionRegistry minion.Registry
|
||||||
if c.Cloud != nil && len(c.MinionRegexp) > 0 {
|
if c.Cloud != nil && len(c.MinionRegexp) > 0 {
|
||||||
var err error
|
var err error
|
||||||
minionRegistry, err = registry.MakeCloudMinionRegistry(c.Cloud, c.MinionRegexp)
|
minionRegistry, err = minion.NewCloudRegistry(c.Cloud, c.MinionRegexp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Failed to initalize cloud minion registry reverting to static registry (%#v)", err)
|
glog.Errorf("Failed to initalize cloud minion registry reverting to static registry (%#v)", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if minionRegistry == nil {
|
if minionRegistry == nil {
|
||||||
minionRegistry = registry.MakeMinionRegistry(c.Minions)
|
minionRegistry = minion.NewRegistry(c.Minions)
|
||||||
}
|
}
|
||||||
if c.HealthCheckMinions {
|
if c.HealthCheckMinions {
|
||||||
minionRegistry = registry.NewHealthyMinionRegistry(minionRegistry, &http.Client{})
|
minionRegistry = minion.NewHealthyRegistry(minionRegistry, &http.Client{})
|
||||||
}
|
}
|
||||||
if c.MinionCacheTTL > 0 {
|
if c.MinionCacheTTL > 0 {
|
||||||
cachingMinionRegistry, err := registry.NewCachingMinionRegistry(minionRegistry, c.MinionCacheTTL)
|
cachingMinionRegistry, err := minion.NewCachingRegistry(minionRegistry, c.MinionCacheTTL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Failed to initialize caching layer, ignoring cache.")
|
glog.Errorf("Failed to initialize caching layer, ignoring cache.")
|
||||||
} else {
|
} else {
|
||||||
@@ -112,17 +119,23 @@ func (m *Master) init(cloud cloudprovider.Interface, podInfoGetter client.PodInf
|
|||||||
podCache := NewPodCache(podInfoGetter, m.podRegistry, time.Second*30)
|
podCache := NewPodCache(podInfoGetter, m.podRegistry, time.Second*30)
|
||||||
go podCache.Loop()
|
go podCache.Loop()
|
||||||
|
|
||||||
endpoints := registry.MakeEndpointController(m.serviceRegistry, m.client)
|
endpoints := endpoint.NewEndpointController(m.serviceRegistry, m.client)
|
||||||
go util.Forever(func() { endpoints.SyncServiceEndpoints() }, time.Second*10)
|
go util.Forever(func() { endpoints.SyncServiceEndpoints() }, time.Second*10)
|
||||||
|
|
||||||
random := rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
|
random := rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
|
||||||
s := scheduler.NewRandomFitScheduler(m.podRegistry, random)
|
s := scheduler.NewRandomFitScheduler(m.podRegistry, random)
|
||||||
m.storage = map[string]apiserver.RESTStorage{
|
m.storage = map[string]apiserver.RESTStorage{
|
||||||
"pods": registry.MakePodRegistryStorage(m.podRegistry, podInfoGetter, s, m.minionRegistry, cloud, podCache),
|
"pods": pod.NewRegistryStorage(&pod.RegistryStorageConfig{
|
||||||
"replicationControllers": registry.NewControllerRegistryStorage(m.controllerRegistry, m.podRegistry),
|
CloudProvider: cloud,
|
||||||
"services": registry.MakeServiceRegistryStorage(m.serviceRegistry, cloud, m.minionRegistry),
|
MinionLister: m.minionRegistry,
|
||||||
"minions": registry.MakeMinionRegistryStorage(m.minionRegistry),
|
PodCache: podCache,
|
||||||
"bindings": registry.MakeBindingStorage(m.podRegistry),
|
PodInfoGetter: podInfoGetter,
|
||||||
|
Registry: m.podRegistry,
|
||||||
|
Scheduler: s,
|
||||||
|
}),
|
||||||
|
"replicationControllers": controller.NewRegistryStorage(m.controllerRegistry, m.podRegistry),
|
||||||
|
"services": service.NewRegistryStorage(m.serviceRegistry, cloud, m.minionRegistry),
|
||||||
|
"minions": minion.NewRegistryStorage(m.minionRegistry),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -23,8 +23,9 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"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"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -32,7 +33,7 @@ import (
|
|||||||
// that cache up to date.
|
// that cache up to date.
|
||||||
type PodCache struct {
|
type PodCache struct {
|
||||||
containerInfo client.PodInfoGetter
|
containerInfo client.PodInfoGetter
|
||||||
pods registry.PodRegistry
|
pods pod.Registry
|
||||||
// This is a map of pod id to a map of container name to the
|
// This is a map of pod id to a map of container name to the
|
||||||
podInfo map[string]api.PodInfo
|
podInfo map[string]api.PodInfo
|
||||||
period time.Duration
|
period time.Duration
|
||||||
@@ -40,7 +41,7 @@ type PodCache struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewPodCache returns a new PodCache which watches container information registered in the given PodRegistry.
|
// NewPodCache returns a new PodCache which watches container information registered in the given PodRegistry.
|
||||||
func NewPodCache(info client.PodInfoGetter, pods registry.PodRegistry, period time.Duration) *PodCache {
|
func NewPodCache(info client.PodInfoGetter, pods pod.Registry, period time.Duration) *PodCache {
|
||||||
return &PodCache{
|
return &PodCache{
|
||||||
containerInfo: info,
|
containerInfo: info,
|
||||||
pods: pods,
|
pods: pods,
|
||||||
|
@@ -22,7 +22,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
|
||||||
"github.com/fsouza/go-dockerclient"
|
"github.com/fsouza/go-dockerclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ func TestPodUpdateAllContainers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pods := []api.Pod{pod}
|
pods := []api.Pod{pod}
|
||||||
mockRegistry := registry.MakeMockPodRegistry(pods)
|
mockRegistry := registrytest.NewPodRegistry(pods)
|
||||||
|
|
||||||
expected := api.PodInfo{"foo": docker.Container{ID: "foo"}}
|
expected := api.PodInfo{"foo": docker.Container{ID: "foo"}}
|
||||||
fake := FakePodInfoGetter{
|
fake := FakePodInfoGetter{
|
||||||
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package binding
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -22,17 +22,18 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BindingStorage implements the RESTStorage interface. When bindings are written, it
|
// BindingStorage implements the RESTStorage interface. When bindings are written, it
|
||||||
// changes the location of the affected pods. This information is eventually reflected
|
// changes the location of the affected pods. This information is eventually reflected
|
||||||
// in the pod's CurrentState.Host field.
|
// in the pod's CurrentState.Host field.
|
||||||
type BindingStorage struct {
|
type BindingStorage struct {
|
||||||
podRegistry PodRegistry
|
podRegistry pod.Registry
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeBindingStorage makes a new BindingStorage backed by the given PodRegistry.
|
// MakeBindingStorage makes a new BindingStorage backed by the given PodRegistry.
|
||||||
func MakeBindingStorage(podRegistry PodRegistry) *BindingStorage {
|
func MakeBindingStorage(podRegistry pod.Registry) *BindingStorage {
|
||||||
return &BindingStorage{
|
return &BindingStorage{
|
||||||
podRegistry: podRegistry,
|
podRegistry: podRegistry,
|
||||||
}
|
}
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package binding
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
@@ -22,22 +22,8 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PodRegistry is an interface implemented by things that know how to store Pod objects.
|
// Registry is an interface for things that know how to store ReplicationControllers.
|
||||||
type PodRegistry interface {
|
type Registry interface {
|
||||||
// ListPods obtains a list of pods that match selector.
|
|
||||||
ListPods(selector labels.Selector) ([]api.Pod, error)
|
|
||||||
// Get a specific pod
|
|
||||||
GetPod(podID string) (*api.Pod, error)
|
|
||||||
// Create a pod based on a specification, schedule it onto a specific machine.
|
|
||||||
CreatePod(machine string, pod api.Pod) error
|
|
||||||
// Update an existing pod
|
|
||||||
UpdatePod(pod api.Pod) error
|
|
||||||
// Delete an existing pod
|
|
||||||
DeletePod(podID string) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// ControllerRegistry is an interface for things that know how to store ReplicationControllers.
|
|
||||||
type ControllerRegistry interface {
|
|
||||||
ListControllers() ([]api.ReplicationController, error)
|
ListControllers() ([]api.ReplicationController, error)
|
||||||
WatchControllers(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
|
WatchControllers(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
|
||||||
GetController(controllerID string) (*api.ReplicationController, error)
|
GetController(controllerID string) (*api.ReplicationController, error)
|
||||||
@@ -45,13 +31,3 @@ type ControllerRegistry interface {
|
|||||||
UpdateController(controller api.ReplicationController) error
|
UpdateController(controller api.ReplicationController) error
|
||||||
DeleteController(controllerID string) error
|
DeleteController(controllerID string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServiceRegistry is an interface for things that know how to store services.
|
|
||||||
type ServiceRegistry interface {
|
|
||||||
ListServices() (api.ServiceList, error)
|
|
||||||
CreateService(svc api.Service) error
|
|
||||||
GetService(name string) (*api.Service, error)
|
|
||||||
DeleteService(name string) error
|
|
||||||
UpdateService(svc api.Service) error
|
|
||||||
UpdateEndpoints(e api.Endpoints) error
|
|
||||||
}
|
|
@@ -14,39 +14,82 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.google.com/p/go-uuid/uuid"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||||
|
|
||||||
|
"code.google.com/p/go-uuid/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ControllerRegistryStorage is an implementation of RESTStorage for the api server.
|
// RegistryStorage stores data for the replication controller service.
|
||||||
type ControllerRegistryStorage struct {
|
// It implements apiserver.RESTStorage.
|
||||||
registry ControllerRegistry
|
type RegistryStorage struct {
|
||||||
podRegistry PodRegistry
|
registry Registry
|
||||||
// Period in between polls when waiting for a controller to complete
|
podRegistry pod.Registry
|
||||||
pollPeriod time.Duration
|
pollPeriod time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewControllerRegistryStorage(registry ControllerRegistry, podRegistry PodRegistry) apiserver.RESTStorage {
|
// NewRegistryStorage returns a new apiserver.RESTStorage for the given
|
||||||
return &ControllerRegistryStorage{
|
// registry and podRegistry.
|
||||||
|
func NewRegistryStorage(registry Registry, podRegistry pod.Registry) apiserver.RESTStorage {
|
||||||
|
return &RegistryStorage{
|
||||||
registry: registry,
|
registry: registry,
|
||||||
podRegistry: podRegistry,
|
podRegistry: podRegistry,
|
||||||
pollPeriod: time.Second * 10,
|
pollPeriod: time.Second * 10,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create registers then given ReplicationController.
|
||||||
|
func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
|
||||||
|
controller, ok := obj.(*api.ReplicationController)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("not a replication controller: %#v", obj)
|
||||||
|
}
|
||||||
|
if len(controller.ID) == 0 {
|
||||||
|
controller.ID = uuid.NewUUID().String()
|
||||||
|
}
|
||||||
|
// Pod Manifest ID should be assigned by the pod API
|
||||||
|
controller.DesiredState.PodTemplate.DesiredState.Manifest.ID = ""
|
||||||
|
if errs := api.ValidateReplicationController(controller); len(errs) > 0 {
|
||||||
|
return nil, fmt.Errorf("Validation errors: %v", errs)
|
||||||
|
}
|
||||||
|
return apiserver.MakeAsync(func() (interface{}, error) {
|
||||||
|
err := rs.registry.CreateController(*controller)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return rs.waitForController(*controller)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete asynchronously deletes the ReplicationController specified by its id.
|
||||||
|
func (rs *RegistryStorage) Delete(id string) (<-chan interface{}, error) {
|
||||||
|
return apiserver.MakeAsync(func() (interface{}, error) {
|
||||||
|
return api.Status{Status: api.StatusSuccess}, rs.registry.DeleteController(id)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get obtains the ReplicationController specified by its id.
|
||||||
|
func (rs *RegistryStorage) Get(id string) (interface{}, error) {
|
||||||
|
controller, err := rs.registry.GetController(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return controller, err
|
||||||
|
}
|
||||||
|
|
||||||
// List obtains a list of ReplicationControllers that match selector.
|
// List obtains a list of ReplicationControllers that match selector.
|
||||||
func (storage *ControllerRegistryStorage) List(selector labels.Selector) (interface{}, error) {
|
func (rs *RegistryStorage) List(selector labels.Selector) (interface{}, error) {
|
||||||
result := api.ReplicationControllerList{}
|
result := api.ReplicationControllerList{}
|
||||||
controllers, err := storage.registry.ListControllers()
|
controllers, err := rs.registry.ListControllers()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for _, controller := range controllers {
|
for _, controller := range controllers {
|
||||||
if selector.Matches(labels.Set(controller.Labels)) {
|
if selector.Matches(labels.Set(controller.Labels)) {
|
||||||
@@ -57,54 +100,14 @@ func (storage *ControllerRegistryStorage) List(selector labels.Selector) (interf
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get obtains the ReplicationController specified by its id.
|
// New creates a new ReplicationController for use with Create and Update.
|
||||||
func (storage *ControllerRegistryStorage) Get(id string) (interface{}, error) {
|
func (rs RegistryStorage) New() interface{} {
|
||||||
controller, err := storage.registry.GetController(id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return controller, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete asynchronously deletes the ReplicationController specified by its id.
|
|
||||||
func (storage *ControllerRegistryStorage) Delete(id string) (<-chan interface{}, error) {
|
|
||||||
return apiserver.MakeAsync(func() (interface{}, error) {
|
|
||||||
return &api.Status{Status: api.StatusSuccess}, storage.registry.DeleteController(id)
|
|
||||||
}), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new ReplicationController for use with Create and Update
|
|
||||||
func (storage *ControllerRegistryStorage) New() interface{} {
|
|
||||||
return &api.ReplicationController{}
|
return &api.ReplicationController{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create registers a given new ReplicationController instance to storage.registry.
|
// Update replaces a given ReplicationController instance with an existing
|
||||||
func (storage *ControllerRegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
|
// instance in storage.registry.
|
||||||
controller, ok := obj.(*api.ReplicationController)
|
func (rs *RegistryStorage) Update(obj interface{}) (<-chan interface{}, error) {
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("not a replication controller: %#v", obj)
|
|
||||||
}
|
|
||||||
if len(controller.ID) == 0 {
|
|
||||||
controller.ID = uuid.NewUUID().String()
|
|
||||||
}
|
|
||||||
// Pod Manifest ID should be assigned by the pod API
|
|
||||||
controller.DesiredState.PodTemplate.DesiredState.Manifest.ID = ""
|
|
||||||
|
|
||||||
if errs := api.ValidateReplicationController(controller); len(errs) > 0 {
|
|
||||||
return nil, fmt.Errorf("Validation errors: %v", errs)
|
|
||||||
}
|
|
||||||
|
|
||||||
return apiserver.MakeAsync(func() (interface{}, error) {
|
|
||||||
err := storage.registry.CreateController(*controller)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return storage.waitForController(*controller)
|
|
||||||
}), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update replaces a given ReplicationController instance with an existing instance in storage.registry.
|
|
||||||
func (storage *ControllerRegistryStorage) Update(obj interface{}) (<-chan interface{}, error) {
|
|
||||||
controller, ok := obj.(*api.ReplicationController)
|
controller, ok := obj.(*api.ReplicationController)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("not a replication controller: %#v", obj)
|
return nil, fmt.Errorf("not a replication controller: %#v", obj)
|
||||||
@@ -113,30 +116,30 @@ func (storage *ControllerRegistryStorage) Update(obj interface{}) (<-chan interf
|
|||||||
return nil, fmt.Errorf("Validation errors: %v", errs)
|
return nil, fmt.Errorf("Validation errors: %v", errs)
|
||||||
}
|
}
|
||||||
return apiserver.MakeAsync(func() (interface{}, error) {
|
return apiserver.MakeAsync(func() (interface{}, error) {
|
||||||
err := storage.registry.UpdateController(*controller)
|
err := rs.registry.UpdateController(*controller)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return storage.waitForController(*controller)
|
return rs.waitForController(*controller)
|
||||||
}), nil
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storage *ControllerRegistryStorage) waitForController(ctrl api.ReplicationController) (interface{}, error) {
|
// Watch returns ReplicationController events via a watch.Interface.
|
||||||
|
// It implements apiserver.ResourceWatcher.
|
||||||
|
func (rs *RegistryStorage) Watch(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
|
||||||
|
return rs.registry.WatchControllers(label, field, resourceVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *RegistryStorage) waitForController(ctrl api.ReplicationController) (interface{}, error) {
|
||||||
for {
|
for {
|
||||||
pods, err := storage.podRegistry.ListPods(labels.Set(ctrl.DesiredState.ReplicaSelector).AsSelector())
|
pods, err := rs.podRegistry.ListPods(labels.Set(ctrl.DesiredState.ReplicaSelector).AsSelector())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctrl, err
|
return ctrl, err
|
||||||
}
|
}
|
||||||
if len(pods) == ctrl.DesiredState.Replicas {
|
if len(pods) == ctrl.DesiredState.Replicas {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
time.Sleep(storage.pollPeriod)
|
time.Sleep(rs.pollPeriod)
|
||||||
}
|
}
|
||||||
return ctrl, nil
|
return ctrl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WatchAll returns ReplicationController events via a watch.Interface, implementing
|
|
||||||
// apiserver.ResourceWatcher.
|
|
||||||
func (storage *ControllerRegistryStorage) Watch(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
|
|
||||||
return storage.registry.WatchControllers(label, field, resourceVersion)
|
|
||||||
}
|
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -26,50 +26,20 @@ import (
|
|||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Why do we have this AND MemoryRegistry?
|
|
||||||
type MockControllerRegistry struct {
|
|
||||||
err error
|
|
||||||
controllers []api.ReplicationController
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MockControllerRegistry) ListControllers() ([]api.ReplicationController, error) {
|
|
||||||
return registry.controllers, registry.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MockControllerRegistry) GetController(ID string) (*api.ReplicationController, error) {
|
|
||||||
return &api.ReplicationController{}, registry.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MockControllerRegistry) CreateController(controller api.ReplicationController) error {
|
|
||||||
return registry.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MockControllerRegistry) UpdateController(controller api.ReplicationController) error {
|
|
||||||
return registry.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MockControllerRegistry) DeleteController(ID string) error {
|
|
||||||
return registry.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MockControllerRegistry) WatchControllers(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
|
|
||||||
return nil, registry.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestListControllersError(t *testing.T) {
|
func TestListControllersError(t *testing.T) {
|
||||||
mockRegistry := MockControllerRegistry{
|
mockRegistry := registrytest.ControllerRegistry{
|
||||||
err: fmt.Errorf("test error"),
|
Err: fmt.Errorf("test error"),
|
||||||
}
|
}
|
||||||
storage := ControllerRegistryStorage{
|
storage := RegistryStorage{
|
||||||
registry: &mockRegistry,
|
registry: &mockRegistry,
|
||||||
}
|
}
|
||||||
controllersObj, err := storage.List(nil)
|
controllersObj, err := storage.List(nil)
|
||||||
controllers := controllersObj.(api.ReplicationControllerList)
|
controllers := controllersObj.(api.ReplicationControllerList)
|
||||||
if err != mockRegistry.err {
|
if err != mockRegistry.Err {
|
||||||
t.Errorf("Expected %#v, Got %#v", mockRegistry.err, err)
|
t.Errorf("Expected %#v, Got %#v", mockRegistry.Err, err)
|
||||||
}
|
}
|
||||||
if len(controllers.Items) != 0 {
|
if len(controllers.Items) != 0 {
|
||||||
t.Errorf("Unexpected non-zero ctrl list: %#v", controllers)
|
t.Errorf("Unexpected non-zero ctrl list: %#v", controllers)
|
||||||
@@ -77,8 +47,8 @@ func TestListControllersError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestListEmptyControllerList(t *testing.T) {
|
func TestListEmptyControllerList(t *testing.T) {
|
||||||
mockRegistry := MockControllerRegistry{}
|
mockRegistry := registrytest.ControllerRegistry{}
|
||||||
storage := ControllerRegistryStorage{
|
storage := RegistryStorage{
|
||||||
registry: &mockRegistry,
|
registry: &mockRegistry,
|
||||||
}
|
}
|
||||||
controllers, err := storage.List(labels.Everything())
|
controllers, err := storage.List(labels.Everything())
|
||||||
@@ -92,8 +62,8 @@ func TestListEmptyControllerList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestListControllerList(t *testing.T) {
|
func TestListControllerList(t *testing.T) {
|
||||||
mockRegistry := MockControllerRegistry{
|
mockRegistry := registrytest.ControllerRegistry{
|
||||||
controllers: []api.ReplicationController{
|
Controllers: []api.ReplicationController{
|
||||||
{
|
{
|
||||||
JSONBase: api.JSONBase{
|
JSONBase: api.JSONBase{
|
||||||
ID: "foo",
|
ID: "foo",
|
||||||
@@ -106,7 +76,7 @@ func TestListControllerList(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
storage := ControllerRegistryStorage{
|
storage := RegistryStorage{
|
||||||
registry: &mockRegistry,
|
registry: &mockRegistry,
|
||||||
}
|
}
|
||||||
controllersObj, err := storage.List(labels.Everything())
|
controllersObj, err := storage.List(labels.Everything())
|
||||||
@@ -127,8 +97,8 @@ func TestListControllerList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestControllerDecode(t *testing.T) {
|
func TestControllerDecode(t *testing.T) {
|
||||||
mockRegistry := MockControllerRegistry{}
|
mockRegistry := registrytest.ControllerRegistry{}
|
||||||
storage := ControllerRegistryStorage{
|
storage := RegistryStorage{
|
||||||
registry: &mockRegistry,
|
registry: &mockRegistry,
|
||||||
}
|
}
|
||||||
controller := &api.ReplicationController{
|
controller := &api.ReplicationController{
|
||||||
@@ -238,16 +208,16 @@ var validPodTemplate = api.PodTemplate{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateController(t *testing.T) {
|
func TestCreateController(t *testing.T) {
|
||||||
mockRegistry := MockControllerRegistry{}
|
mockRegistry := registrytest.ControllerRegistry{}
|
||||||
mockPodRegistry := MockPodRegistry{
|
mockPodRegistry := registrytest.PodRegistry{
|
||||||
pods: []api.Pod{
|
Pods: []api.Pod{
|
||||||
{
|
{
|
||||||
JSONBase: api.JSONBase{ID: "foo"},
|
JSONBase: api.JSONBase{ID: "foo"},
|
||||||
Labels: map[string]string{"a": "b"},
|
Labels: map[string]string{"a": "b"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
storage := ControllerRegistryStorage{
|
storage := RegistryStorage{
|
||||||
registry: &mockRegistry,
|
registry: &mockRegistry,
|
||||||
podRegistry: &mockPodRegistry,
|
podRegistry: &mockPodRegistry,
|
||||||
pollPeriod: time.Millisecond * 1,
|
pollPeriod: time.Millisecond * 1,
|
||||||
@@ -276,7 +246,7 @@ func TestCreateController(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mockPodRegistry.Lock()
|
mockPodRegistry.Lock()
|
||||||
mockPodRegistry.pods = []api.Pod{
|
mockPodRegistry.Pods = []api.Pod{
|
||||||
{
|
{
|
||||||
JSONBase: api.JSONBase{ID: "foo"},
|
JSONBase: api.JSONBase{ID: "foo"},
|
||||||
Labels: map[string]string{"a": "b"},
|
Labels: map[string]string{"a": "b"},
|
||||||
@@ -297,8 +267,8 @@ func TestCreateController(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestControllerStorageValidatesCreate(t *testing.T) {
|
func TestControllerStorageValidatesCreate(t *testing.T) {
|
||||||
mockRegistry := MockControllerRegistry{}
|
mockRegistry := registrytest.ControllerRegistry{}
|
||||||
storage := ControllerRegistryStorage{
|
storage := RegistryStorage{
|
||||||
registry: &mockRegistry,
|
registry: &mockRegistry,
|
||||||
podRegistry: nil,
|
podRegistry: nil,
|
||||||
pollPeriod: time.Millisecond * 1,
|
pollPeriod: time.Millisecond * 1,
|
||||||
@@ -328,13 +298,12 @@ func TestControllerStorageValidatesCreate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestControllerStorageValidatesUpdate(t *testing.T) {
|
func TestControllerStorageValidatesUpdate(t *testing.T) {
|
||||||
mockRegistry := MockControllerRegistry{}
|
mockRegistry := registrytest.ControllerRegistry{}
|
||||||
storage := ControllerRegistryStorage{
|
storage := RegistryStorage{
|
||||||
registry: &mockRegistry,
|
registry: &mockRegistry,
|
||||||
podRegistry: nil,
|
podRegistry: nil,
|
||||||
pollPeriod: time.Millisecond * 1,
|
pollPeriod: time.Millisecond * 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
failureCases := map[string]api.ReplicationController{
|
failureCases := map[string]api.ReplicationController{
|
||||||
"empty ID": {
|
"empty ID": {
|
||||||
JSONBase: api.JSONBase{ID: ""},
|
JSONBase: api.JSONBase{ID: ""},
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package endpoint
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -24,42 +24,27 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"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/service"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func MakeEndpointController(serviceRegistry ServiceRegistry, client *client.Client) *EndpointController {
|
// A EndpointController manages service endpoints.
|
||||||
|
type EndpointController struct {
|
||||||
|
client *client.Client
|
||||||
|
serviceRegistry service.Registry
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEndpointController returns a new *EndpointController.
|
||||||
|
func NewEndpointController(serviceRegistry service.Registry, client *client.Client) *EndpointController {
|
||||||
return &EndpointController{
|
return &EndpointController{
|
||||||
serviceRegistry: serviceRegistry,
|
serviceRegistry: serviceRegistry,
|
||||||
client: client,
|
client: client,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type EndpointController struct {
|
// SyncServiceEndpoints syncs service endpoints.
|
||||||
serviceRegistry ServiceRegistry
|
|
||||||
client *client.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func findPort(manifest *api.ContainerManifest, portName util.IntOrString) (int, error) {
|
|
||||||
if ((portName.Kind == util.IntstrString && len(portName.StrVal) == 0) ||
|
|
||||||
(portName.Kind == util.IntstrInt && portName.IntVal == 0)) &&
|
|
||||||
len(manifest.Containers[0].Ports) > 0 {
|
|
||||||
return manifest.Containers[0].Ports[0].ContainerPort, nil
|
|
||||||
}
|
|
||||||
if portName.Kind == util.IntstrInt {
|
|
||||||
return portName.IntVal, nil
|
|
||||||
}
|
|
||||||
name := portName.StrVal
|
|
||||||
for _, container := range manifest.Containers {
|
|
||||||
for _, port := range container.Ports {
|
|
||||||
if port.Name == name {
|
|
||||||
return port.ContainerPort, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1, fmt.Errorf("no suitable port for manifest: %s", manifest.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *EndpointController) SyncServiceEndpoints() error {
|
func (e *EndpointController) SyncServiceEndpoints() error {
|
||||||
services, err := e.serviceRegistry.ListServices()
|
services, err := e.serviceRegistry.ListServices()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -98,3 +83,24 @@ func (e *EndpointController) SyncServiceEndpoints() error {
|
|||||||
}
|
}
|
||||||
return resultErr
|
return resultErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// findPort locates the container port for the given manifest and portName.
|
||||||
|
func findPort(manifest *api.ContainerManifest, portName util.IntOrString) (int, error) {
|
||||||
|
if ((portName.Kind == util.IntstrString && len(portName.StrVal) == 0) ||
|
||||||
|
(portName.Kind == util.IntstrInt && portName.IntVal == 0)) &&
|
||||||
|
len(manifest.Containers[0].Ports) > 0 {
|
||||||
|
return manifest.Containers[0].Ports[0].ContainerPort, nil
|
||||||
|
}
|
||||||
|
if portName.Kind == util.IntstrInt {
|
||||||
|
return portName.IntVal, nil
|
||||||
|
}
|
||||||
|
name := portName.StrVal
|
||||||
|
for _, container := range manifest.Containers {
|
||||||
|
for _, port := range container.Ports {
|
||||||
|
if port.Name == name {
|
||||||
|
return port.ContainerPort, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1, fmt.Errorf("no suitable port for manifest: %s", manifest.ID)
|
||||||
|
}
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package endpoint
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -24,6 +24,7 @@ import (
|
|||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -82,7 +83,6 @@ func TestFindPort(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if port != 8080 {
|
if port != 8080 {
|
||||||
t.Errorf("Expected 8080, Got %d", port)
|
t.Errorf("Expected 8080, Got %d", port)
|
||||||
}
|
}
|
||||||
@@ -90,7 +90,6 @@ func TestFindPort(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if port != 8000 {
|
if port != 8000 {
|
||||||
t.Errorf("Expected 8000, Got %d", port)
|
t.Errorf("Expected 8000, Got %d", port)
|
||||||
}
|
}
|
||||||
@@ -110,7 +109,6 @@ func TestFindPort(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if port != 8080 {
|
if port != 8080 {
|
||||||
t.Errorf("Expected 8080, Got %d", port)
|
t.Errorf("Expected 8080, Got %d", port)
|
||||||
}
|
}
|
||||||
@@ -118,7 +116,6 @@ func TestFindPort(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if port != 8080 {
|
if port != 8080 {
|
||||||
t.Errorf("Expected 8080, Got %d", port)
|
t.Errorf("Expected 8080, Got %d", port)
|
||||||
}
|
}
|
||||||
@@ -132,10 +129,8 @@ func TestSyncEndpointsEmpty(t *testing.T) {
|
|||||||
}
|
}
|
||||||
testServer := httptest.NewTLSServer(&fakeHandler)
|
testServer := httptest.NewTLSServer(&fakeHandler)
|
||||||
client := client.New(testServer.URL, nil)
|
client := client.New(testServer.URL, nil)
|
||||||
|
serviceRegistry := registrytest.ServiceRegistry{}
|
||||||
serviceRegistry := MockServiceRegistry{}
|
endpoints := NewEndpointController(&serviceRegistry, client)
|
||||||
|
|
||||||
endpoints := MakeEndpointController(&serviceRegistry, client)
|
|
||||||
err := endpoints.SyncServiceEndpoints()
|
err := endpoints.SyncServiceEndpoints()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
@@ -151,15 +146,13 @@ func TestSyncEndpointsError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
testServer := httptest.NewTLSServer(&fakeHandler)
|
testServer := httptest.NewTLSServer(&fakeHandler)
|
||||||
client := client.New(testServer.URL, nil)
|
client := client.New(testServer.URL, nil)
|
||||||
|
serviceRegistry := registrytest.ServiceRegistry{
|
||||||
serviceRegistry := MockServiceRegistry{
|
Err: fmt.Errorf("test error"),
|
||||||
err: fmt.Errorf("test error"),
|
|
||||||
}
|
}
|
||||||
|
endpoints := NewEndpointController(&serviceRegistry, client)
|
||||||
endpoints := MakeEndpointController(&serviceRegistry, client)
|
|
||||||
err := endpoints.SyncServiceEndpoints()
|
err := endpoints.SyncServiceEndpoints()
|
||||||
if err != serviceRegistry.err {
|
if err != serviceRegistry.Err {
|
||||||
t.Errorf("Errors don't match: %#v %#v", err, serviceRegistry.err)
|
t.Errorf("Errors don't match: %#v %#v", err, serviceRegistry.Err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,9 +164,8 @@ func TestSyncEndpointsItems(t *testing.T) {
|
|||||||
}
|
}
|
||||||
testServer := httptest.NewTLSServer(&fakeHandler)
|
testServer := httptest.NewTLSServer(&fakeHandler)
|
||||||
client := client.New(testServer.URL, nil)
|
client := client.New(testServer.URL, nil)
|
||||||
|
serviceRegistry := registrytest.ServiceRegistry{
|
||||||
serviceRegistry := MockServiceRegistry{
|
List: api.ServiceList{
|
||||||
list: api.ServiceList{
|
|
||||||
Items: []api.Service{
|
Items: []api.Service{
|
||||||
{
|
{
|
||||||
Selector: map[string]string{
|
Selector: map[string]string{
|
||||||
@@ -183,15 +175,13 @@ func TestSyncEndpointsItems(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
endpoints := NewEndpointController(&serviceRegistry, client)
|
||||||
endpoints := MakeEndpointController(&serviceRegistry, client)
|
|
||||||
err := endpoints.SyncServiceEndpoints()
|
err := endpoints.SyncServiceEndpoints()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
if len(serviceRegistry.Endpoints.Endpoints) != 1 {
|
||||||
if len(serviceRegistry.endpoints.Endpoints) != 1 {
|
t.Errorf("Unexpected endpoints update: %#v", serviceRegistry.Endpoints)
|
||||||
t.Errorf("Unexpected endpoints update: %#v", serviceRegistry.endpoints)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,9 +191,8 @@ func TestSyncEndpointsPodError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
testServer := httptest.NewTLSServer(&fakeHandler)
|
testServer := httptest.NewTLSServer(&fakeHandler)
|
||||||
client := client.New(testServer.URL, nil)
|
client := client.New(testServer.URL, nil)
|
||||||
|
serviceRegistry := registrytest.ServiceRegistry{
|
||||||
serviceRegistry := MockServiceRegistry{
|
List: api.ServiceList{
|
||||||
list: api.ServiceList{
|
|
||||||
Items: []api.Service{
|
Items: []api.Service{
|
||||||
{
|
{
|
||||||
Selector: map[string]string{
|
Selector: map[string]string{
|
||||||
@@ -213,8 +202,7 @@ func TestSyncEndpointsPodError(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
endpoints := NewEndpointController(&serviceRegistry, client)
|
||||||
endpoints := MakeEndpointController(&serviceRegistry, client)
|
|
||||||
err := endpoints.SyncServiceEndpoints()
|
err := endpoints.SyncServiceEndpoints()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("Unexpected non-error")
|
t.Error("Unexpected non-error")
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package etcd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -22,27 +22,31 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/minion"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Need to add a reconciler loop that makes sure that things in pods are reflected into
|
// TODO: Need to add a reconciler loop that makes sure that things in pods are reflected into
|
||||||
// kubelet (and vice versa)
|
// kubelet (and vice versa)
|
||||||
|
|
||||||
// EtcdRegistry implements PodRegistry, ControllerRegistry and ServiceRegistry with backed by etcd.
|
// Registry implements PodRegistry, ControllerRegistry and ServiceRegistry
|
||||||
type EtcdRegistry struct {
|
// with backed by etcd.
|
||||||
helper tools.EtcdHelper
|
type Registry struct {
|
||||||
|
tools.EtcdHelper
|
||||||
manifestFactory ManifestFactory
|
manifestFactory ManifestFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeEtcdRegistry creates an etcd registry.
|
// NewRegistry creates an etcd registry.
|
||||||
// 'client' is the connection to etcd
|
func NewRegistry(client tools.EtcdClient, machines minion.Registry) *Registry {
|
||||||
// 'machines' is the list of machines
|
registry := &Registry{
|
||||||
// 'scheduler' is the scheduling algorithm to use.
|
EtcdHelper: tools.EtcdHelper{
|
||||||
func MakeEtcdRegistry(client tools.EtcdClient, machines MinionRegistry) *EtcdRegistry {
|
client,
|
||||||
registry := &EtcdRegistry{
|
api.Codec,
|
||||||
helper: tools.EtcdHelper{client, api.Codec, api.ResourceVersioner},
|
api.ResourceVersioner,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
registry.manifestFactory = &BasicManifestFactory{
|
registry.manifestFactory = &BasicManifestFactory{
|
||||||
serviceRegistry: registry,
|
serviceRegistry: registry,
|
||||||
@@ -55,11 +59,10 @@ func makePodKey(podID string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ListPods obtains a list of pods that match selector.
|
// ListPods obtains a list of pods that match selector.
|
||||||
func (registry *EtcdRegistry) ListPods(selector labels.Selector) ([]api.Pod, error) {
|
func (r *Registry) ListPods(selector labels.Selector) ([]api.Pod, error) {
|
||||||
allPods := []api.Pod{}
|
allPods := []api.Pod{}
|
||||||
filteredPods := []api.Pod{}
|
filteredPods := []api.Pod{}
|
||||||
err := registry.helper.ExtractList("/registry/pods", &allPods)
|
if err := r.ExtractList("/registry/pods", &allPods); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, pod := range allPods {
|
for _, pod := range allPods {
|
||||||
@@ -75,10 +78,9 @@ func (registry *EtcdRegistry) ListPods(selector labels.Selector) ([]api.Pod, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetPod gets a specific pod specified by its ID.
|
// GetPod gets a specific pod specified by its ID.
|
||||||
func (registry *EtcdRegistry) GetPod(podID string) (*api.Pod, error) {
|
func (r *Registry) GetPod(podID string) (*api.Pod, error) {
|
||||||
var pod api.Pod
|
var pod api.Pod
|
||||||
err := registry.helper.ExtractObj(makePodKey(podID), &pod, false)
|
if err := r.ExtractObj(makePodKey(podID), &pod, false); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// TODO: Currently nothing sets CurrentState.Host. We need a feedback loop that sets
|
// TODO: Currently nothing sets CurrentState.Host. We need a feedback loop that sets
|
||||||
@@ -93,33 +95,26 @@ func makeContainerKey(machine string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreatePod creates a pod based on a specification, schedule it onto a specific machine.
|
// CreatePod creates a pod based on a specification, schedule it onto a specific machine.
|
||||||
func (registry *EtcdRegistry) CreatePod(machine string, pod api.Pod) error {
|
func (r *Registry) CreatePod(machine string, pod api.Pod) error {
|
||||||
// Set current status to "Waiting".
|
// Set current status to "Waiting".
|
||||||
pod.CurrentState.Status = api.PodWaiting
|
pod.CurrentState.Status = api.PodWaiting
|
||||||
pod.CurrentState.Host = ""
|
pod.CurrentState.Host = ""
|
||||||
|
|
||||||
// DesiredState.Host == "" is a signal to the scheduler that this pod needs scheduling.
|
// DesiredState.Host == "" is a signal to the scheduler that this pod needs scheduling.
|
||||||
pod.DesiredState.Status = api.PodRunning
|
pod.DesiredState.Status = api.PodRunning
|
||||||
pod.DesiredState.Host = ""
|
pod.DesiredState.Host = ""
|
||||||
|
if err := r.CreateObj(makePodKey(pod.ID), &pod); err != nil {
|
||||||
err := registry.helper.CreateObj(makePodKey(pod.ID), &pod)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Until scheduler separation is completed, just assign here.
|
// TODO: Until scheduler separation is completed, just assign here.
|
||||||
return registry.AssignPod(pod.ID, machine)
|
return r.AssignPod(pod.ID, machine)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssignPod assigns the given pod to the given machine.
|
// AssignPod assigns the given pod to the given machine.
|
||||||
// TODO: hook this up via apiserver, not by calling it from CreatePod().
|
// TODO: hook this up via apiserver, not by calling it from CreatePod().
|
||||||
func (registry *EtcdRegistry) AssignPod(podID string, machine string) error {
|
func (r *Registry) AssignPod(podID string, machine string) error {
|
||||||
podKey := makePodKey(podID)
|
podKey := makePodKey(podID)
|
||||||
var finalPod *api.Pod
|
var finalPod *api.Pod
|
||||||
err := registry.helper.AtomicUpdate(
|
err := r.AtomicUpdate(podKey, &api.Pod{}, func(obj interface{}) (interface{}, error) {
|
||||||
podKey,
|
|
||||||
&api.Pod{},
|
|
||||||
func(obj interface{}) (interface{}, error) {
|
|
||||||
pod, ok := obj.(*api.Pod)
|
pod, ok := obj.(*api.Pod)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("unexpected object: %#v", obj)
|
return nil, fmt.Errorf("unexpected object: %#v", obj)
|
||||||
@@ -127,32 +122,25 @@ func (registry *EtcdRegistry) AssignPod(podID string, machine string) error {
|
|||||||
pod.DesiredState.Host = machine
|
pod.DesiredState.Host = machine
|
||||||
finalPod = pod
|
finalPod = pod
|
||||||
return pod, nil
|
return pod, nil
|
||||||
},
|
})
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: move this to a watch/rectification loop.
|
// TODO: move this to a watch/rectification loop.
|
||||||
manifest, err := registry.manifestFactory.MakeManifest(machine, *finalPod)
|
manifest, err := r.manifestFactory.MakeManifest(machine, *finalPod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
contKey := makeContainerKey(machine)
|
contKey := makeContainerKey(machine)
|
||||||
err = registry.helper.AtomicUpdate(
|
err = r.AtomicUpdate(contKey, &api.ContainerManifestList{}, func(in interface{}) (interface{}, error) {
|
||||||
contKey,
|
|
||||||
&api.ContainerManifestList{},
|
|
||||||
func(in interface{}) (interface{}, error) {
|
|
||||||
manifests := *in.(*api.ContainerManifestList)
|
manifests := *in.(*api.ContainerManifestList)
|
||||||
manifests.Items = append(manifests.Items, manifest)
|
manifests.Items = append(manifests.Items, manifest)
|
||||||
return manifests, nil
|
return manifests, nil
|
||||||
},
|
})
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Don't strand stuff. This is a terrible hack that won't be needed
|
// Don't strand stuff. This is a terrible hack that won't be needed
|
||||||
// when the above TODO is fixed.
|
// when the above TODO is fixed.
|
||||||
err2 := registry.helper.Delete(podKey, false)
|
err2 := r.Delete(podKey, false)
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
glog.Errorf("Probably stranding a pod, couldn't delete %v: %#v", podKey, err2)
|
glog.Errorf("Probably stranding a pod, couldn't delete %v: %#v", podKey, err2)
|
||||||
}
|
}
|
||||||
@@ -160,41 +148,38 @@ func (registry *EtcdRegistry) AssignPod(podID string, machine string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (registry *EtcdRegistry) UpdatePod(pod api.Pod) error {
|
func (r *Registry) UpdatePod(pod api.Pod) error {
|
||||||
return fmt.Errorf("unimplemented!")
|
return fmt.Errorf("unimplemented!")
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeletePod deletes an existing pod specified by its ID.
|
// DeletePod deletes an existing pod specified by its ID.
|
||||||
func (registry *EtcdRegistry) DeletePod(podID string) error {
|
func (r *Registry) DeletePod(podID string) error {
|
||||||
var pod api.Pod
|
var pod api.Pod
|
||||||
podKey := makePodKey(podID)
|
podKey := makePodKey(podID)
|
||||||
err := registry.helper.ExtractObj(podKey, &pod, false)
|
err := r.ExtractObj(podKey, &pod, false)
|
||||||
if tools.IsEtcdNotFound(err) {
|
if tools.IsEtcdNotFound(err) {
|
||||||
return apiserver.NewNotFoundErr("pod", podID)
|
return apiserver.NewNotFoundErr("pod", podID)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// First delete the pod, so a scheduler doesn't notice it getting removed from the
|
// First delete the pod, so a scheduler doesn't notice it getting removed from the
|
||||||
// machine and attempt to put it somewhere.
|
// machine and attempt to put it somewhere.
|
||||||
err = registry.helper.Delete(podKey, true)
|
err = r.Delete(podKey, true)
|
||||||
if tools.IsEtcdNotFound(err) {
|
if tools.IsEtcdNotFound(err) {
|
||||||
return apiserver.NewNotFoundErr("pod", podID)
|
return apiserver.NewNotFoundErr("pod", podID)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
machine := pod.DesiredState.Host
|
machine := pod.DesiredState.Host
|
||||||
if machine == "" {
|
if machine == "" {
|
||||||
// Pod was never scheduled anywhere, just return.
|
// Pod was never scheduled anywhere, just return.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next, remove the pod from the machine atomically.
|
// Next, remove the pod from the machine atomically.
|
||||||
contKey := makeContainerKey(machine)
|
contKey := makeContainerKey(machine)
|
||||||
return registry.helper.AtomicUpdate(contKey, &api.ContainerManifestList{}, func(in interface{}) (interface{}, error) {
|
return r.AtomicUpdate(contKey, &api.ContainerManifestList{}, func(in interface{}) (interface{}, error) {
|
||||||
manifests := in.(*api.ContainerManifestList)
|
manifests := in.(*api.ContainerManifestList)
|
||||||
newManifests := make([]api.ContainerManifest, 0, len(manifests.Items))
|
newManifests := make([]api.ContainerManifest, 0, len(manifests.Items))
|
||||||
found := false
|
found := false
|
||||||
@@ -217,18 +202,18 @@ func (registry *EtcdRegistry) DeletePod(podID string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ListControllers obtains a list of ReplicationControllers.
|
// ListControllers obtains a list of ReplicationControllers.
|
||||||
func (registry *EtcdRegistry) ListControllers() ([]api.ReplicationController, error) {
|
func (r *Registry) ListControllers() ([]api.ReplicationController, error) {
|
||||||
var controllers []api.ReplicationController
|
var controllers []api.ReplicationController
|
||||||
err := registry.helper.ExtractList("/registry/controllers", &controllers)
|
err := r.ExtractList("/registry/controllers", &controllers)
|
||||||
return controllers, err
|
return controllers, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// WatchControllers begins watching for new, changed, or deleted controllers.
|
// WatchControllers begins watching for new, changed, or deleted controllers.
|
||||||
func (registry *EtcdRegistry) WatchControllers(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
|
func (r *Registry) WatchControllers(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
|
||||||
if !field.Empty() {
|
if !field.Empty() {
|
||||||
return nil, fmt.Errorf("no field selector implemented for controllers")
|
return nil, fmt.Errorf("no field selector implemented for controllers")
|
||||||
}
|
}
|
||||||
return registry.helper.WatchList("/registry/controllers", resourceVersion, func(obj interface{}) bool {
|
return r.WatchList("/registry/controllers", resourceVersion, func(obj interface{}) bool {
|
||||||
return label.Matches(labels.Set(obj.(*api.ReplicationController).Labels))
|
return label.Matches(labels.Set(obj.(*api.ReplicationController).Labels))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -238,10 +223,10 @@ func makeControllerKey(id string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetController gets a specific ReplicationController specified by its ID.
|
// GetController gets a specific ReplicationController specified by its ID.
|
||||||
func (registry *EtcdRegistry) GetController(controllerID string) (*api.ReplicationController, error) {
|
func (r *Registry) GetController(controllerID string) (*api.ReplicationController, error) {
|
||||||
var controller api.ReplicationController
|
var controller api.ReplicationController
|
||||||
key := makeControllerKey(controllerID)
|
key := makeControllerKey(controllerID)
|
||||||
err := registry.helper.ExtractObj(key, &controller, false)
|
err := r.ExtractObj(key, &controller, false)
|
||||||
if tools.IsEtcdNotFound(err) {
|
if tools.IsEtcdNotFound(err) {
|
||||||
return nil, apiserver.NewNotFoundErr("replicationController", controllerID)
|
return nil, apiserver.NewNotFoundErr("replicationController", controllerID)
|
||||||
}
|
}
|
||||||
@@ -252,8 +237,8 @@ func (registry *EtcdRegistry) GetController(controllerID string) (*api.Replicati
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateController creates a new ReplicationController.
|
// CreateController creates a new ReplicationController.
|
||||||
func (registry *EtcdRegistry) CreateController(controller api.ReplicationController) error {
|
func (r *Registry) CreateController(controller api.ReplicationController) error {
|
||||||
err := registry.helper.CreateObj(makeControllerKey(controller.ID), controller)
|
err := r.CreateObj(makeControllerKey(controller.ID), controller)
|
||||||
if tools.IsEtcdNodeExist(err) {
|
if tools.IsEtcdNodeExist(err) {
|
||||||
return apiserver.NewAlreadyExistsErr("replicationController", controller.ID)
|
return apiserver.NewAlreadyExistsErr("replicationController", controller.ID)
|
||||||
}
|
}
|
||||||
@@ -261,14 +246,14 @@ func (registry *EtcdRegistry) CreateController(controller api.ReplicationControl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateController replaces an existing ReplicationController.
|
// UpdateController replaces an existing ReplicationController.
|
||||||
func (registry *EtcdRegistry) UpdateController(controller api.ReplicationController) error {
|
func (r *Registry) UpdateController(controller api.ReplicationController) error {
|
||||||
return registry.helper.SetObj(makeControllerKey(controller.ID), controller)
|
return r.SetObj(makeControllerKey(controller.ID), controller)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteController deletes a ReplicationController specified by its ID.
|
// DeleteController deletes a ReplicationController specified by its ID.
|
||||||
func (registry *EtcdRegistry) DeleteController(controllerID string) error {
|
func (r *Registry) DeleteController(controllerID string) error {
|
||||||
key := makeControllerKey(controllerID)
|
key := makeControllerKey(controllerID)
|
||||||
err := registry.helper.Delete(key, false)
|
err := r.Delete(key, false)
|
||||||
if tools.IsEtcdNotFound(err) {
|
if tools.IsEtcdNotFound(err) {
|
||||||
return apiserver.NewNotFoundErr("replicationController", controllerID)
|
return apiserver.NewNotFoundErr("replicationController", controllerID)
|
||||||
}
|
}
|
||||||
@@ -280,15 +265,15 @@ func makeServiceKey(name string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ListServices obtains a list of Services.
|
// ListServices obtains a list of Services.
|
||||||
func (registry *EtcdRegistry) ListServices() (api.ServiceList, error) {
|
func (r *Registry) ListServices() (api.ServiceList, error) {
|
||||||
var list api.ServiceList
|
var list api.ServiceList
|
||||||
err := registry.helper.ExtractList("/registry/services/specs", &list.Items)
|
err := r.ExtractList("/registry/services/specs", &list.Items)
|
||||||
return list, err
|
return list, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateService creates a new Service.
|
// CreateService creates a new Service.
|
||||||
func (registry *EtcdRegistry) CreateService(svc api.Service) error {
|
func (r *Registry) CreateService(svc api.Service) error {
|
||||||
err := registry.helper.CreateObj(makeServiceKey(svc.ID), svc)
|
err := r.CreateObj(makeServiceKey(svc.ID), svc)
|
||||||
if tools.IsEtcdNodeExist(err) {
|
if tools.IsEtcdNodeExist(err) {
|
||||||
return apiserver.NewAlreadyExistsErr("service", svc.ID)
|
return apiserver.NewAlreadyExistsErr("service", svc.ID)
|
||||||
}
|
}
|
||||||
@@ -296,10 +281,10 @@ func (registry *EtcdRegistry) CreateService(svc api.Service) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetService obtains a Service specified by its name.
|
// GetService obtains a Service specified by its name.
|
||||||
func (registry *EtcdRegistry) GetService(name string) (*api.Service, error) {
|
func (r *Registry) GetService(name string) (*api.Service, error) {
|
||||||
key := makeServiceKey(name)
|
key := makeServiceKey(name)
|
||||||
var svc api.Service
|
var svc api.Service
|
||||||
err := registry.helper.ExtractObj(key, &svc, false)
|
err := r.ExtractObj(key, &svc, false)
|
||||||
if tools.IsEtcdNotFound(err) {
|
if tools.IsEtcdNotFound(err) {
|
||||||
return nil, apiserver.NewNotFoundErr("service", name)
|
return nil, apiserver.NewNotFoundErr("service", name)
|
||||||
}
|
}
|
||||||
@@ -314,9 +299,9 @@ func makeServiceEndpointsKey(name string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeleteService deletes a Service specified by its name.
|
// DeleteService deletes a Service specified by its name.
|
||||||
func (registry *EtcdRegistry) DeleteService(name string) error {
|
func (r *Registry) DeleteService(name string) error {
|
||||||
key := makeServiceKey(name)
|
key := makeServiceKey(name)
|
||||||
err := registry.helper.Delete(key, true)
|
err := r.Delete(key, true)
|
||||||
if tools.IsEtcdNotFound(err) {
|
if tools.IsEtcdNotFound(err) {
|
||||||
return apiserver.NewNotFoundErr("service", name)
|
return apiserver.NewNotFoundErr("service", name)
|
||||||
}
|
}
|
||||||
@@ -324,7 +309,7 @@ func (registry *EtcdRegistry) DeleteService(name string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
key = makeServiceEndpointsKey(name)
|
key = makeServiceEndpointsKey(name)
|
||||||
err = registry.helper.Delete(key, true)
|
err = r.Delete(key, true)
|
||||||
if !tools.IsEtcdNotFound(err) {
|
if !tools.IsEtcdNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -332,12 +317,14 @@ func (registry *EtcdRegistry) DeleteService(name string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateService replaces an existing Service.
|
// UpdateService replaces an existing Service.
|
||||||
func (registry *EtcdRegistry) UpdateService(svc api.Service) error {
|
func (r *Registry) UpdateService(svc api.Service) error {
|
||||||
return registry.helper.SetObj(makeServiceKey(svc.ID), svc)
|
return r.SetObj(makeServiceKey(svc.ID), svc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateEndpoints update Endpoints of a Service.
|
// UpdateEndpoints update Endpoints of a Service.
|
||||||
func (registry *EtcdRegistry) UpdateEndpoints(e api.Endpoints) error {
|
func (r *Registry) UpdateEndpoints(e api.Endpoints) error {
|
||||||
updateFunc := func(interface{}) (interface{}, error) { return e, nil }
|
return r.AtomicUpdate(makeServiceEndpointsKey(e.ID), &api.Endpoints{},
|
||||||
return registry.helper.AtomicUpdate(makeServiceEndpointsKey(e.ID), &api.Endpoints{}, updateFunc)
|
func(interface{}) (interface{}, error) {
|
||||||
|
return e, nil
|
||||||
|
})
|
||||||
}
|
}
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package etcd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -23,14 +23,17 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/minion"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
||||||
|
|
||||||
"github.com/coreos/go-etcd/etcd"
|
"github.com/coreos/go-etcd/etcd"
|
||||||
)
|
)
|
||||||
|
|
||||||
func MakeTestEtcdRegistry(client tools.EtcdClient, machines []string) *EtcdRegistry {
|
func MakeTestEtcdRegistry(client tools.EtcdClient, machines []string) *Registry {
|
||||||
registry := MakeEtcdRegistry(client, MakeMinionRegistry(machines))
|
registry := NewRegistry(client, minion.NewRegistry(machines))
|
||||||
registry.manifestFactory = &BasicManifestFactory{
|
registry.manifestFactory = &BasicManifestFactory{
|
||||||
serviceRegistry: &MockServiceRegistry{},
|
serviceRegistry: ®istrytest.ServiceRegistry{},
|
||||||
}
|
}
|
||||||
return registry
|
return registry
|
||||||
}
|
}
|
@@ -14,10 +14,11 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package etcd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ManifestFactory interface {
|
type ManifestFactory interface {
|
||||||
@@ -26,11 +27,11 @@ type ManifestFactory interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type BasicManifestFactory struct {
|
type BasicManifestFactory struct {
|
||||||
serviceRegistry ServiceRegistry
|
serviceRegistry service.Registry
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BasicManifestFactory) MakeManifest(machine string, pod api.Pod) (api.ContainerManifest, error) {
|
func (b *BasicManifestFactory) MakeManifest(machine string, pod api.Pod) (api.ContainerManifest, error) {
|
||||||
envVars, err := GetServiceEnvironmentVariables(b.serviceRegistry, machine)
|
envVars, err := service.GetServiceEnvironmentVariables(b.serviceRegistry, machine)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return api.ContainerManifest{}, err
|
return api.ContainerManifest{}, err
|
||||||
}
|
}
|
@@ -14,18 +14,19 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package etcd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMakeManifestNoServices(t *testing.T) {
|
func TestMakeManifestNoServices(t *testing.T) {
|
||||||
registry := MockServiceRegistry{}
|
registry := registrytest.ServiceRegistry{}
|
||||||
factory := &BasicManifestFactory{
|
factory := &BasicManifestFactory{
|
||||||
serviceRegistry: ®istry,
|
serviceRegistry: ®istry,
|
||||||
}
|
}
|
||||||
@@ -58,8 +59,8 @@ func TestMakeManifestNoServices(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMakeManifestServices(t *testing.T) {
|
func TestMakeManifestServices(t *testing.T) {
|
||||||
registry := MockServiceRegistry{
|
registry := registrytest.ServiceRegistry{
|
||||||
list: api.ServiceList{
|
List: api.ServiceList{
|
||||||
Items: []api.Service{
|
Items: []api.Service{
|
||||||
{
|
{
|
||||||
JSONBase: api.JSONBase{ID: "test"},
|
JSONBase: api.JSONBase{ID: "test"},
|
||||||
@@ -134,8 +135,8 @@ func TestMakeManifestServices(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMakeManifestServicesExistingEnvVar(t *testing.T) {
|
func TestMakeManifestServicesExistingEnvVar(t *testing.T) {
|
||||||
registry := MockServiceRegistry{
|
registry := registrytest.ServiceRegistry{
|
||||||
list: api.ServiceList{
|
List: api.ServiceList{
|
||||||
Items: []api.Service{
|
Items: []api.Service{
|
||||||
{
|
{
|
||||||
JSONBase: api.JSONBase{ID: "test"},
|
JSONBase: api.JSONBase{ID: "test"},
|
191
pkg/registry/memory/memory.go
Normal file
191
pkg/registry/memory/memory.go
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
|
||||||
|
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 memory
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||||
|
)
|
||||||
|
|
||||||
|
// An implementation of PodRegistry and ControllerRegistry that is backed
|
||||||
|
// by memory. Mainly used for testing.
|
||||||
|
type Registry struct {
|
||||||
|
podData map[string]api.Pod
|
||||||
|
controllerData map[string]api.ReplicationController
|
||||||
|
serviceData map[string]api.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRegistry returns a new Registry.
|
||||||
|
func NewRegistry() *Registry {
|
||||||
|
return &Registry{
|
||||||
|
podData: map[string]api.Pod{},
|
||||||
|
controllerData: map[string]api.ReplicationController{},
|
||||||
|
serviceData: map[string]api.Service{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateController registers the given replication controller.
|
||||||
|
func (r *Registry) CreateController(controller api.ReplicationController) error {
|
||||||
|
r.controllerData[controller.ID] = controller
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreatePod registers the given pod.
|
||||||
|
func (r *Registry) CreatePod(machine string, pod api.Pod) error {
|
||||||
|
r.podData[pod.ID] = pod
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateService registers the given service.
|
||||||
|
func (r *Registry) CreateService(svc api.Service) error {
|
||||||
|
r.serviceData[svc.ID] = svc
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteController deletes the named replication controller from the
|
||||||
|
// registry.
|
||||||
|
func (r *Registry) DeleteController(controllerID string) error {
|
||||||
|
if _, ok := r.controllerData[controllerID]; !ok {
|
||||||
|
return apiserver.NewNotFoundErr("replicationController", controllerID)
|
||||||
|
}
|
||||||
|
delete(r.controllerData, controllerID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeletePod deletes the named pod from the registry.
|
||||||
|
func (r *Registry) DeletePod(podID string) error {
|
||||||
|
if _, ok := r.podData[podID]; !ok {
|
||||||
|
return apiserver.NewNotFoundErr("pod", podID)
|
||||||
|
}
|
||||||
|
delete(r.podData, podID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteService deletes the named service from the registry.
|
||||||
|
// It returns an error if the service is not found in the registry.
|
||||||
|
func (r *Registry) DeleteService(name string) error {
|
||||||
|
if _, ok := r.serviceData[name]; !ok {
|
||||||
|
return apiserver.NewNotFoundErr("service", name)
|
||||||
|
}
|
||||||
|
delete(r.serviceData, name)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetController returns an *api.ReplicationController for the name controller.
|
||||||
|
// It returns an error if the controller is not found in the registry.
|
||||||
|
func (r *Registry) GetController(controllerID string) (*api.ReplicationController, error) {
|
||||||
|
controller, found := r.controllerData[controllerID]
|
||||||
|
if found {
|
||||||
|
return &controller, nil
|
||||||
|
} else {
|
||||||
|
return nil, apiserver.NewNotFoundErr("replicationController", controllerID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPod returns an *api.Pod for the named pod.
|
||||||
|
// It returns an error if the pod is not found in the registry.
|
||||||
|
func (r *Registry) GetPod(podID string) (*api.Pod, error) {
|
||||||
|
pod, found := r.podData[podID]
|
||||||
|
if found {
|
||||||
|
return &pod, nil
|
||||||
|
} else {
|
||||||
|
return nil, apiserver.NewNotFoundErr("pod", podID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetService returns an *api.Service for the named service.
|
||||||
|
// It returns an error if the service is not found in the registry.
|
||||||
|
func (r *Registry) GetService(name string) (*api.Service, error) {
|
||||||
|
svc, found := r.serviceData[name]
|
||||||
|
if !found {
|
||||||
|
return nil, apiserver.NewNotFoundErr("service", name)
|
||||||
|
}
|
||||||
|
return &svc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListControllers returns all registered replication controllers.
|
||||||
|
func (r *Registry) ListControllers() ([]api.ReplicationController, error) {
|
||||||
|
result := []api.ReplicationController{}
|
||||||
|
for _, value := range r.controllerData {
|
||||||
|
result = append(result, value)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListPods returns all registered pods for the given selector.
|
||||||
|
func (r *Registry) ListPods(selector labels.Selector) ([]api.Pod, error) {
|
||||||
|
result := []api.Pod{}
|
||||||
|
for _, value := range r.podData {
|
||||||
|
if selector.Matches(labels.Set(value.Labels)) {
|
||||||
|
result = append(result, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListServices returns all registered services.
|
||||||
|
func (r *Registry) ListServices() (api.ServiceList, error) {
|
||||||
|
var list []api.Service
|
||||||
|
for _, value := range r.serviceData {
|
||||||
|
list = append(list, value)
|
||||||
|
}
|
||||||
|
return api.ServiceList{Items: list}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateController updates the given controller in the registry.
|
||||||
|
// It returns an error if the controller is not found in the registry.
|
||||||
|
func (r *Registry) UpdateController(controller api.ReplicationController) error {
|
||||||
|
if _, ok := r.controllerData[controller.ID]; !ok {
|
||||||
|
return apiserver.NewNotFoundErr("replicationController", controller.ID)
|
||||||
|
}
|
||||||
|
r.controllerData[controller.ID] = controller
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateEndpoints always returns nil.
|
||||||
|
func (r *Registry) UpdateEndpoints(e api.Endpoints) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdatePod updates the given pod in the registry.
|
||||||
|
// It returns an error if the pod is not found in the registry.
|
||||||
|
func (r *Registry) UpdatePod(pod api.Pod) error {
|
||||||
|
if _, ok := r.podData[pod.ID]; !ok {
|
||||||
|
return apiserver.NewNotFoundErr("pod", pod.ID)
|
||||||
|
}
|
||||||
|
r.podData[pod.ID] = pod
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateService updates the given service in the registry.
|
||||||
|
// It returns an error if the service is not found in the registry.
|
||||||
|
func (r *Registry) UpdateService(svc api.Service) error {
|
||||||
|
if _, ok := r.serviceData[svc.ID]; !ok {
|
||||||
|
return apiserver.NewNotFoundErr("service", svc.ID)
|
||||||
|
}
|
||||||
|
return r.CreateService(svc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WatchControllers always returns an error.
|
||||||
|
// It is not implemented.
|
||||||
|
func (r *Registry) WatchControllers(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
|
||||||
|
return nil, errors.New("unimplemented")
|
||||||
|
}
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package memory
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
@@ -25,32 +25,30 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestListPodsEmpty(t *testing.T) {
|
func TestListPodsEmpty(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
pods, err := registry.ListPods(labels.Everything())
|
pods, err := registry.ListPods(labels.Everything())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(pods) != 0 {
|
if len(pods) != 0 {
|
||||||
t.Errorf("Unexpected pod list: %#v", pods)
|
t.Errorf("Unexpected pod list: %#v", pods)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMemoryListPods(t *testing.T) {
|
func TestMemoryListPods(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
registry.CreatePod("machine", api.Pod{JSONBase: api.JSONBase{ID: "foo"}})
|
registry.CreatePod("machine", api.Pod{JSONBase: api.JSONBase{ID: "foo"}})
|
||||||
pods, err := registry.ListPods(labels.Everything())
|
pods, err := registry.ListPods(labels.Everything())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(pods) != 1 || pods[0].ID != "foo" {
|
if len(pods) != 1 || pods[0].ID != "foo" {
|
||||||
t.Errorf("Unexpected pod list: %#v", pods)
|
t.Errorf("Unexpected pod list: %#v", pods)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMemoryGetPods(t *testing.T) {
|
func TestMemoryGetPods(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
pod, err := registry.GetPod("foo")
|
pod, err := registry.GetPod("foo")
|
||||||
if !apiserver.IsNotFound(err) {
|
if !apiserver.IsNotFound(err) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -62,7 +60,7 @@ func TestMemoryGetPods(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMemorySetGetPods(t *testing.T) {
|
func TestMemorySetGetPods(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
expectedPod := api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
expectedPod := api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
||||||
registry.CreatePod("machine", expectedPod)
|
registry.CreatePod("machine", expectedPod)
|
||||||
pod, err := registry.GetPod("foo")
|
pod, err := registry.GetPod("foo")
|
||||||
@@ -76,7 +74,7 @@ func TestMemorySetGetPods(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMemoryUpdatePods(t *testing.T) {
|
func TestMemoryUpdatePods(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
pod := api.Pod{
|
pod := api.Pod{
|
||||||
JSONBase: api.JSONBase{
|
JSONBase: api.JSONBase{
|
||||||
ID: "foo",
|
ID: "foo",
|
||||||
@@ -96,7 +94,7 @@ func TestMemoryUpdatePods(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMemorySetUpdateGetPods(t *testing.T) {
|
func TestMemorySetUpdateGetPods(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
oldPod := api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
oldPod := api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
||||||
expectedPod := api.Pod{
|
expectedPod := api.Pod{
|
||||||
JSONBase: api.JSONBase{
|
JSONBase: api.JSONBase{
|
||||||
@@ -119,7 +117,7 @@ func TestMemorySetUpdateGetPods(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMemoryDeletePods(t *testing.T) {
|
func TestMemoryDeletePods(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
err := registry.DeletePod("foo")
|
err := registry.DeletePod("foo")
|
||||||
if !apiserver.IsNotFound(err) {
|
if !apiserver.IsNotFound(err) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -131,7 +129,7 @@ func TestMemoryDeletePods(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMemorySetDeleteGetPods(t *testing.T) {
|
func TestMemorySetDeleteGetPods(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
expectedPod := api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
expectedPod := api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
||||||
registry.CreatePod("machine", expectedPod)
|
registry.CreatePod("machine", expectedPod)
|
||||||
registry.DeletePod("foo")
|
registry.DeletePod("foo")
|
||||||
@@ -146,7 +144,7 @@ func TestMemorySetDeleteGetPods(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestListControllersEmpty(t *testing.T) {
|
func TestListControllersEmpty(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
ctls, err := registry.ListControllers()
|
ctls, err := registry.ListControllers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
@@ -158,7 +156,7 @@ func TestListControllersEmpty(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMemoryListControllers(t *testing.T) {
|
func TestMemoryListControllers(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
registry.CreateController(api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}})
|
registry.CreateController(api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}})
|
||||||
ctls, err := registry.ListControllers()
|
ctls, err := registry.ListControllers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -171,7 +169,7 @@ func TestMemoryListControllers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMemoryGetController(t *testing.T) {
|
func TestMemoryGetController(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
ctl, err := registry.GetController("foo")
|
ctl, err := registry.GetController("foo")
|
||||||
if !apiserver.IsNotFound(err) {
|
if !apiserver.IsNotFound(err) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -183,7 +181,7 @@ func TestMemoryGetController(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMemorySetGetControllers(t *testing.T) {
|
func TestMemorySetGetControllers(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
expectedController := api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}
|
expectedController := api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}
|
||||||
registry.CreateController(expectedController)
|
registry.CreateController(expectedController)
|
||||||
ctl, err := registry.GetController("foo")
|
ctl, err := registry.GetController("foo")
|
||||||
@@ -197,7 +195,7 @@ func TestMemorySetGetControllers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMemoryUpdateController(t *testing.T) {
|
func TestMemoryUpdateController(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
ctl := api.ReplicationController{
|
ctl := api.ReplicationController{
|
||||||
JSONBase: api.JSONBase{
|
JSONBase: api.JSONBase{
|
||||||
ID: "foo",
|
ID: "foo",
|
||||||
@@ -217,7 +215,7 @@ func TestMemoryUpdateController(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMemorySetUpdateGetControllers(t *testing.T) {
|
func TestMemorySetUpdateGetControllers(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
oldController := api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}
|
oldController := api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}
|
||||||
expectedController := api.ReplicationController{
|
expectedController := api.ReplicationController{
|
||||||
JSONBase: api.JSONBase{
|
JSONBase: api.JSONBase{
|
||||||
@@ -240,7 +238,7 @@ func TestMemorySetUpdateGetControllers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMemoryDeleteController(t *testing.T) {
|
func TestMemoryDeleteController(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
err := registry.DeleteController("foo")
|
err := registry.DeleteController("foo")
|
||||||
if !apiserver.IsNotFound(err) {
|
if !apiserver.IsNotFound(err) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -252,7 +250,7 @@ func TestMemoryDeleteController(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMemorySetDeleteGetControllers(t *testing.T) {
|
func TestMemorySetDeleteGetControllers(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
expectedController := api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}
|
expectedController := api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}
|
||||||
registry.CreateController(expectedController)
|
registry.CreateController(expectedController)
|
||||||
registry.DeleteController("foo")
|
registry.DeleteController("foo")
|
||||||
@@ -267,7 +265,7 @@ func TestMemorySetDeleteGetControllers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestListServicesEmpty(t *testing.T) {
|
func TestListServicesEmpty(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
svcs, err := registry.ListServices()
|
svcs, err := registry.ListServices()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
@@ -279,7 +277,7 @@ func TestListServicesEmpty(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMemoryListServices(t *testing.T) {
|
func TestMemoryListServices(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
registry.CreateService(api.Service{JSONBase: api.JSONBase{ID: "foo"}})
|
registry.CreateService(api.Service{JSONBase: api.JSONBase{ID: "foo"}})
|
||||||
svcs, err := registry.ListServices()
|
svcs, err := registry.ListServices()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -292,7 +290,7 @@ func TestMemoryListServices(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMemoryGetService(t *testing.T) {
|
func TestMemoryGetService(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
svc, err := registry.GetService("foo")
|
svc, err := registry.GetService("foo")
|
||||||
if !apiserver.IsNotFound(err) {
|
if !apiserver.IsNotFound(err) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -304,7 +302,7 @@ func TestMemoryGetService(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMemorySetGetServices(t *testing.T) {
|
func TestMemorySetGetServices(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
expectedService := api.Service{JSONBase: api.JSONBase{ID: "foo"}}
|
expectedService := api.Service{JSONBase: api.JSONBase{ID: "foo"}}
|
||||||
registry.CreateService(expectedService)
|
registry.CreateService(expectedService)
|
||||||
svc, err := registry.GetService("foo")
|
svc, err := registry.GetService("foo")
|
||||||
@@ -318,7 +316,7 @@ func TestMemorySetGetServices(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMemoryUpdateService(t *testing.T) {
|
func TestMemoryUpdateService(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
svc := api.Service{
|
svc := api.Service{
|
||||||
JSONBase: api.JSONBase{
|
JSONBase: api.JSONBase{
|
||||||
ID: "foo",
|
ID: "foo",
|
||||||
@@ -336,7 +334,7 @@ func TestMemoryUpdateService(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMemorySetUpdateGetServices(t *testing.T) {
|
func TestMemorySetUpdateGetServices(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
oldService := api.Service{JSONBase: api.JSONBase{ID: "foo"}}
|
oldService := api.Service{JSONBase: api.JSONBase{ID: "foo"}}
|
||||||
expectedService := api.Service{
|
expectedService := api.Service{
|
||||||
JSONBase: api.JSONBase{
|
JSONBase: api.JSONBase{
|
||||||
@@ -357,7 +355,7 @@ func TestMemorySetUpdateGetServices(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMemoryDeleteService(t *testing.T) {
|
func TestMemoryDeleteService(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
err := registry.DeleteService("foo")
|
err := registry.DeleteService("foo")
|
||||||
if !apiserver.IsNotFound(err) {
|
if !apiserver.IsNotFound(err) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -369,7 +367,7 @@ func TestMemoryDeleteService(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMemorySetDeleteGetServices(t *testing.T) {
|
func TestMemorySetDeleteGetServices(t *testing.T) {
|
||||||
registry := MakeMemoryRegistry()
|
registry := NewRegistry()
|
||||||
expectedService := api.Service{JSONBase: api.JSONBase{ID: "foo"}}
|
expectedService := api.Service{JSONBase: api.JSONBase{ID: "foo"}}
|
||||||
registry.CreateService(expectedService)
|
registry.CreateService(expectedService)
|
||||||
registry.DeleteService("foo")
|
registry.DeleteService("foo")
|
@@ -1,165 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 Google Inc. All rights reserved.
|
|
||||||
|
|
||||||
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 registry
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
|
||||||
)
|
|
||||||
|
|
||||||
// An implementation of PodRegistry and ControllerRegistry that is backed by memory
|
|
||||||
// Mainly used for testing.
|
|
||||||
type MemoryRegistry struct {
|
|
||||||
podData map[string]api.Pod
|
|
||||||
controllerData map[string]api.ReplicationController
|
|
||||||
serviceData map[string]api.Service
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeMemoryRegistry() *MemoryRegistry {
|
|
||||||
return &MemoryRegistry{
|
|
||||||
podData: map[string]api.Pod{},
|
|
||||||
controllerData: map[string]api.ReplicationController{},
|
|
||||||
serviceData: map[string]api.Service{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MemoryRegistry) ListPods(selector labels.Selector) ([]api.Pod, error) {
|
|
||||||
result := []api.Pod{}
|
|
||||||
for _, value := range registry.podData {
|
|
||||||
if selector.Matches(labels.Set(value.Labels)) {
|
|
||||||
result = append(result, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MemoryRegistry) GetPod(podID string) (*api.Pod, error) {
|
|
||||||
pod, found := registry.podData[podID]
|
|
||||||
if found {
|
|
||||||
return &pod, nil
|
|
||||||
} else {
|
|
||||||
return nil, apiserver.NewNotFoundErr("pod", podID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MemoryRegistry) CreatePod(machine string, pod api.Pod) error {
|
|
||||||
registry.podData[pod.ID] = pod
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MemoryRegistry) DeletePod(podID string) error {
|
|
||||||
if _, ok := registry.podData[podID]; !ok {
|
|
||||||
return apiserver.NewNotFoundErr("pod", podID)
|
|
||||||
}
|
|
||||||
delete(registry.podData, podID)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MemoryRegistry) UpdatePod(pod api.Pod) error {
|
|
||||||
if _, ok := registry.podData[pod.ID]; !ok {
|
|
||||||
return apiserver.NewNotFoundErr("pod", pod.ID)
|
|
||||||
}
|
|
||||||
registry.podData[pod.ID] = pod
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MemoryRegistry) ListControllers() ([]api.ReplicationController, error) {
|
|
||||||
result := []api.ReplicationController{}
|
|
||||||
for _, value := range registry.controllerData {
|
|
||||||
result = append(result, value)
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MemoryRegistry) WatchControllers(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
|
|
||||||
return nil, errors.New("unimplemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MemoryRegistry) GetController(controllerID string) (*api.ReplicationController, error) {
|
|
||||||
controller, found := registry.controllerData[controllerID]
|
|
||||||
if found {
|
|
||||||
return &controller, nil
|
|
||||||
} else {
|
|
||||||
return nil, apiserver.NewNotFoundErr("replicationController", controllerID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MemoryRegistry) CreateController(controller api.ReplicationController) error {
|
|
||||||
registry.controllerData[controller.ID] = controller
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MemoryRegistry) DeleteController(controllerID string) error {
|
|
||||||
if _, ok := registry.controllerData[controllerID]; !ok {
|
|
||||||
return apiserver.NewNotFoundErr("replicationController", controllerID)
|
|
||||||
}
|
|
||||||
delete(registry.controllerData, controllerID)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MemoryRegistry) UpdateController(controller api.ReplicationController) error {
|
|
||||||
if _, ok := registry.controllerData[controller.ID]; !ok {
|
|
||||||
return apiserver.NewNotFoundErr("replicationController", controller.ID)
|
|
||||||
}
|
|
||||||
registry.controllerData[controller.ID] = controller
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MemoryRegistry) ListServices() (api.ServiceList, error) {
|
|
||||||
var list []api.Service
|
|
||||||
for _, value := range registry.serviceData {
|
|
||||||
list = append(list, value)
|
|
||||||
}
|
|
||||||
return api.ServiceList{Items: list}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MemoryRegistry) CreateService(svc api.Service) error {
|
|
||||||
registry.serviceData[svc.ID] = svc
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MemoryRegistry) GetService(name string) (*api.Service, error) {
|
|
||||||
svc, found := registry.serviceData[name]
|
|
||||||
if found {
|
|
||||||
return &svc, nil
|
|
||||||
} else {
|
|
||||||
return nil, apiserver.NewNotFoundErr("service", name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MemoryRegistry) DeleteService(name string) error {
|
|
||||||
if _, ok := registry.serviceData[name]; !ok {
|
|
||||||
return apiserver.NewNotFoundErr("service", name)
|
|
||||||
}
|
|
||||||
delete(registry.serviceData, name)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MemoryRegistry) UpdateService(svc api.Service) error {
|
|
||||||
if _, ok := registry.serviceData[svc.ID]; !ok {
|
|
||||||
return apiserver.NewNotFoundErr("service", svc.ID)
|
|
||||||
}
|
|
||||||
return registry.CreateService(svc)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MemoryRegistry) UpdateEndpoints(e api.Endpoints) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package minion
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
@@ -32,8 +32,8 @@ func (SystemClock) Now() time.Time {
|
|||||||
return time.Now()
|
return time.Now()
|
||||||
}
|
}
|
||||||
|
|
||||||
type CachingMinionRegistry struct {
|
type CachingRegistry struct {
|
||||||
delegate MinionRegistry
|
delegate Registry
|
||||||
ttl time.Duration
|
ttl time.Duration
|
||||||
minions []string
|
minions []string
|
||||||
lastUpdate int64
|
lastUpdate int64
|
||||||
@@ -41,12 +41,12 @@ type CachingMinionRegistry struct {
|
|||||||
clock Clock
|
clock Clock
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCachingMinionRegistry(delegate MinionRegistry, ttl time.Duration) (MinionRegistry, error) {
|
func NewCachingRegistry(delegate Registry, ttl time.Duration) (Registry, error) {
|
||||||
list, err := delegate.List()
|
list, err := delegate.List()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &CachingMinionRegistry{
|
return &CachingRegistry{
|
||||||
delegate: delegate,
|
delegate: delegate,
|
||||||
ttl: ttl,
|
ttl: ttl,
|
||||||
minions: list,
|
minions: list,
|
||||||
@@ -55,44 +55,16 @@ func NewCachingMinionRegistry(delegate MinionRegistry, ttl time.Duration) (Minio
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CachingMinionRegistry) List() ([]string, error) {
|
func (r *CachingRegistry) Contains(minion string) (bool, error) {
|
||||||
if c.expired() {
|
if r.expired() {
|
||||||
err := c.refresh(false)
|
if err := r.refresh(false); err != nil {
|
||||||
if err != nil {
|
|
||||||
return c.minions, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c.minions, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CachingMinionRegistry) Insert(minion string) error {
|
|
||||||
err := c.delegate.Insert(minion)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.refresh(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CachingMinionRegistry) Delete(minion string) error {
|
|
||||||
err := c.delegate.Delete(minion)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.refresh(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CachingMinionRegistry) Contains(minion string) (bool, error) {
|
|
||||||
if c.expired() {
|
|
||||||
err := c.refresh(false)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// block updates in the middle of a contains.
|
// block updates in the middle of a contains.
|
||||||
c.lock.RLock()
|
r.lock.RLock()
|
||||||
defer c.lock.RUnlock()
|
defer r.lock.RUnlock()
|
||||||
for _, name := range c.minions {
|
for _, name := range r.minions {
|
||||||
if name == minion {
|
if name == minion {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
@@ -100,23 +72,46 @@ func (c *CachingMinionRegistry) Contains(minion string) (bool, error) {
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *CachingRegistry) Delete(minion string) error {
|
||||||
|
if err := r.delegate.Delete(minion); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return r.refresh(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CachingRegistry) Insert(minion string) error {
|
||||||
|
if err := r.delegate.Insert(minion); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return r.refresh(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CachingRegistry) List() ([]string, error) {
|
||||||
|
if r.expired() {
|
||||||
|
if err := r.refresh(false); err != nil {
|
||||||
|
return r.minions, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r.minions, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CachingRegistry) expired() bool {
|
||||||
|
var unix int64
|
||||||
|
atomic.SwapInt64(&unix, r.lastUpdate)
|
||||||
|
return r.clock.Now().Sub(time.Unix(r.lastUpdate, 0)) > r.ttl
|
||||||
|
}
|
||||||
|
|
||||||
// refresh updates the current store. It double checks expired under lock with the assumption
|
// refresh updates the current store. It double checks expired under lock with the assumption
|
||||||
// of optimistic concurrency with the other functions.
|
// of optimistic concurrency with the other functions.
|
||||||
func (c *CachingMinionRegistry) refresh(force bool) error {
|
func (r *CachingRegistry) refresh(force bool) error {
|
||||||
c.lock.Lock()
|
r.lock.Lock()
|
||||||
defer c.lock.Unlock()
|
defer r.lock.Unlock()
|
||||||
if force || c.expired() {
|
if force || r.expired() {
|
||||||
var err error
|
var err error
|
||||||
c.minions, err = c.delegate.List()
|
r.minions, err = r.delegate.List()
|
||||||
time := c.clock.Now()
|
time := r.clock.Now()
|
||||||
atomic.SwapInt64(&c.lastUpdate, time.Unix())
|
atomic.SwapInt64(&r.lastUpdate, time.Unix())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CachingMinionRegistry) expired() bool {
|
|
||||||
var unix int64
|
|
||||||
atomic.SwapInt64(&unix, c.lastUpdate)
|
|
||||||
return c.clock.Now().Sub(time.Unix(c.lastUpdate, 0)) > c.ttl
|
|
||||||
}
|
|
@@ -14,12 +14,14 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package minion
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
|
||||||
)
|
)
|
||||||
|
|
||||||
type fakeClock struct {
|
type fakeClock struct {
|
||||||
@@ -34,9 +36,9 @@ func TestCachingHit(t *testing.T) {
|
|||||||
fakeClock := fakeClock{
|
fakeClock := fakeClock{
|
||||||
now: time.Unix(0, 0),
|
now: time.Unix(0, 0),
|
||||||
}
|
}
|
||||||
fakeRegistry := MakeMockMinionRegistry([]string{"m1", "m2"})
|
fakeRegistry := registrytest.NewMinionRegistry([]string{"m1", "m2"})
|
||||||
expected := []string{"m1", "m2", "m3"}
|
expected := []string{"m1", "m2", "m3"}
|
||||||
cache := CachingMinionRegistry{
|
cache := CachingRegistry{
|
||||||
delegate: fakeRegistry,
|
delegate: fakeRegistry,
|
||||||
ttl: 1 * time.Second,
|
ttl: 1 * time.Second,
|
||||||
clock: &fakeClock,
|
clock: &fakeClock,
|
||||||
@@ -56,9 +58,9 @@ func TestCachingMiss(t *testing.T) {
|
|||||||
fakeClock := fakeClock{
|
fakeClock := fakeClock{
|
||||||
now: time.Unix(0, 0),
|
now: time.Unix(0, 0),
|
||||||
}
|
}
|
||||||
fakeRegistry := MakeMockMinionRegistry([]string{"m1", "m2"})
|
fakeRegistry := registrytest.NewMinionRegistry([]string{"m1", "m2"})
|
||||||
expected := []string{"m1", "m2", "m3"}
|
expected := []string{"m1", "m2", "m3"}
|
||||||
cache := CachingMinionRegistry{
|
cache := CachingRegistry{
|
||||||
delegate: fakeRegistry,
|
delegate: fakeRegistry,
|
||||||
ttl: 1 * time.Second,
|
ttl: 1 * time.Second,
|
||||||
clock: &fakeClock,
|
clock: &fakeClock,
|
||||||
@@ -70,9 +72,8 @@ func TestCachingMiss(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
if !reflect.DeepEqual(list, fakeRegistry.Minions) {
|
||||||
if !reflect.DeepEqual(list, fakeRegistry.minions) {
|
t.Errorf("expected: %v, got %v", fakeRegistry.Minions, list)
|
||||||
t.Errorf("expected: %v, got %v", fakeRegistry.minions, list)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,9 +81,9 @@ func TestCachingInsert(t *testing.T) {
|
|||||||
fakeClock := fakeClock{
|
fakeClock := fakeClock{
|
||||||
now: time.Unix(0, 0),
|
now: time.Unix(0, 0),
|
||||||
}
|
}
|
||||||
fakeRegistry := MakeMockMinionRegistry([]string{"m1", "m2"})
|
fakeRegistry := registrytest.NewMinionRegistry([]string{"m1", "m2"})
|
||||||
expected := []string{"m1", "m2", "m3"}
|
expected := []string{"m1", "m2", "m3"}
|
||||||
cache := CachingMinionRegistry{
|
cache := CachingRegistry{
|
||||||
delegate: fakeRegistry,
|
delegate: fakeRegistry,
|
||||||
ttl: 1 * time.Second,
|
ttl: 1 * time.Second,
|
||||||
clock: &fakeClock,
|
clock: &fakeClock,
|
||||||
@@ -93,14 +94,12 @@ func TestCachingInsert(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
list, err := cache.List()
|
list, err := cache.List()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
if !reflect.DeepEqual(list, fakeRegistry.Minions) {
|
||||||
if !reflect.DeepEqual(list, fakeRegistry.minions) {
|
t.Errorf("expected: %v, got %v", fakeRegistry.Minions, list)
|
||||||
t.Errorf("expected: %v, got %v", fakeRegistry.minions, list)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,9 +107,9 @@ func TestCachingDelete(t *testing.T) {
|
|||||||
fakeClock := fakeClock{
|
fakeClock := fakeClock{
|
||||||
now: time.Unix(0, 0),
|
now: time.Unix(0, 0),
|
||||||
}
|
}
|
||||||
fakeRegistry := MakeMockMinionRegistry([]string{"m1", "m2"})
|
fakeRegistry := registrytest.NewMinionRegistry([]string{"m1", "m2"})
|
||||||
expected := []string{"m1", "m2", "m3"}
|
expected := []string{"m1", "m2", "m3"}
|
||||||
cache := CachingMinionRegistry{
|
cache := CachingRegistry{
|
||||||
delegate: fakeRegistry,
|
delegate: fakeRegistry,
|
||||||
ttl: 1 * time.Second,
|
ttl: 1 * time.Second,
|
||||||
clock: &fakeClock,
|
clock: &fakeClock,
|
||||||
@@ -121,13 +120,11 @@ func TestCachingDelete(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
list, err := cache.List()
|
list, err := cache.List()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
if !reflect.DeepEqual(list, fakeRegistry.Minions) {
|
||||||
if !reflect.DeepEqual(list, fakeRegistry.minions) {
|
t.Errorf("expected: %v, got %v", fakeRegistry.Minions, list)
|
||||||
t.Errorf("expected: %v, got %v", fakeRegistry.minions, list)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package minion
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -22,37 +22,20 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CloudMinionRegistry struct {
|
type CloudRegistry struct {
|
||||||
cloud cloudprovider.Interface
|
cloud cloudprovider.Interface
|
||||||
matchRE string
|
matchRE string
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeCloudMinionRegistry(cloud cloudprovider.Interface, matchRE string) (*CloudMinionRegistry, error) {
|
func NewCloudRegistry(cloud cloudprovider.Interface, matchRE string) (*CloudRegistry, error) {
|
||||||
return &CloudMinionRegistry{
|
return &CloudRegistry{
|
||||||
cloud: cloud,
|
cloud: cloud,
|
||||||
matchRE: matchRE,
|
matchRE: matchRE,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CloudMinionRegistry) List() ([]string, error) {
|
func (r *CloudRegistry) Contains(minion string) (bool, error) {
|
||||||
instances, ok := c.cloud.Instances()
|
instances, err := r.List()
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("cloud doesn't support instances")
|
|
||||||
}
|
|
||||||
|
|
||||||
return instances.List(c.matchRE)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CloudMinionRegistry) Insert(minion string) error {
|
|
||||||
return fmt.Errorf("unsupported")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CloudMinionRegistry) Delete(minion string) error {
|
|
||||||
return fmt.Errorf("unsupported")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CloudMinionRegistry) Contains(minion string) (bool, error) {
|
|
||||||
instances, err := c.List()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@@ -63,3 +46,19 @@ func (c *CloudMinionRegistry) Contains(minion string) (bool, error) {
|
|||||||
}
|
}
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r CloudRegistry) Delete(minion string) error {
|
||||||
|
return fmt.Errorf("unsupported")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r CloudRegistry) Insert(minion string) error {
|
||||||
|
return fmt.Errorf("unsupported")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CloudRegistry) List() ([]string, error) {
|
||||||
|
instances, ok := r.cloud.Instances()
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("cloud doesn't support instances")
|
||||||
|
}
|
||||||
|
return instances.List(r.matchRE)
|
||||||
|
}
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package minion
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -28,7 +28,7 @@ func TestCloudList(t *testing.T) {
|
|||||||
fakeCloud := cloudprovider.FakeCloud{
|
fakeCloud := cloudprovider.FakeCloud{
|
||||||
Machines: instances,
|
Machines: instances,
|
||||||
}
|
}
|
||||||
registry, err := MakeCloudMinionRegistry(&fakeCloud, ".*")
|
registry, err := NewCloudRegistry(&fakeCloud, ".*")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -48,7 +48,7 @@ func TestCloudContains(t *testing.T) {
|
|||||||
fakeCloud := cloudprovider.FakeCloud{
|
fakeCloud := cloudprovider.FakeCloud{
|
||||||
Machines: instances,
|
Machines: instances,
|
||||||
}
|
}
|
||||||
registry, err := MakeCloudMinionRegistry(&fakeCloud, ".*")
|
registry, err := NewCloudRegistry(&fakeCloud, ".*")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@ func TestCloudListRegexp(t *testing.T) {
|
|||||||
fakeCloud := cloudprovider.FakeCloud{
|
fakeCloud := cloudprovider.FakeCloud{
|
||||||
Machines: instances,
|
Machines: instances,
|
||||||
}
|
}
|
||||||
registry, err := MakeCloudMinionRegistry(&fakeCloud, "m[0-9]+")
|
registry, err := NewCloudRegistry(&fakeCloud, "m[0-9]+")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
@@ -14,42 +14,65 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package minion
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/health"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/health"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HealthyMinionRegistry struct {
|
type HealthyRegistry struct {
|
||||||
delegate MinionRegistry
|
delegate Registry
|
||||||
client health.HTTPGetInterface
|
client health.HTTPGetInterface
|
||||||
port int
|
port int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHealthyMinionRegistry(delegate MinionRegistry, client *http.Client) MinionRegistry {
|
func NewHealthyRegistry(delegate Registry, client *http.Client) Registry {
|
||||||
return &HealthyMinionRegistry{
|
return &HealthyRegistry{
|
||||||
delegate: delegate,
|
delegate: delegate,
|
||||||
client: client,
|
client: client,
|
||||||
port: 10250,
|
port: 10250,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HealthyMinionRegistry) makeMinionURL(minion string) string {
|
func (r *HealthyRegistry) Contains(minion string) (bool, error) {
|
||||||
return fmt.Sprintf("http://%s:%d/healthz", minion, h.port)
|
contains, err := r.delegate.Contains(minion)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if !contains {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
status, err := health.DoHTTPCheck(r.makeMinionURL(minion), r.client)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if status == health.Unhealthy {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HealthyMinionRegistry) List() (currentMinions []string, err error) {
|
func (r *HealthyRegistry) Delete(minion string) error {
|
||||||
|
return r.delegate.Delete(minion)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HealthyRegistry) Insert(minion string) error {
|
||||||
|
return r.delegate.Insert(minion)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HealthyRegistry) List() (currentMinions []string, err error) {
|
||||||
var result []string
|
var result []string
|
||||||
list, err := h.delegate.List()
|
list, err := r.delegate.List()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
for _, minion := range list {
|
for _, minion := range list {
|
||||||
status, err := health.DoHTTPCheck(h.makeMinionURL(minion), h.client)
|
status, err := health.DoHTTPCheck(r.makeMinionURL(minion), r.client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("%s failed health check with error: %s", minion, err)
|
glog.Errorf("%s failed health check with error: %s", minion, err)
|
||||||
continue
|
continue
|
||||||
@@ -61,28 +84,6 @@ func (h *HealthyMinionRegistry) List() (currentMinions []string, err error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HealthyMinionRegistry) Insert(minion string) error {
|
func (r *HealthyRegistry) makeMinionURL(minion string) string {
|
||||||
return h.delegate.Insert(minion)
|
return fmt.Sprintf("http://%s:%d/healthz", minion, r.port)
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HealthyMinionRegistry) Delete(minion string) error {
|
|
||||||
return h.delegate.Delete(minion)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HealthyMinionRegistry) Contains(minion string) (bool, error) {
|
|
||||||
contains, err := h.delegate.Contains(minion)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if !contains {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
status, err := health.DoHTTPCheck(h.makeMinionURL(minion), h.client)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if status == health.Unhealthy {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}
|
}
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package minion
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -22,6 +22,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
|
||||||
)
|
)
|
||||||
|
|
||||||
type alwaysYes struct{}
|
type alwaysYes struct{}
|
||||||
@@ -38,41 +40,33 @@ func (alwaysYes) Get(url string) (*http.Response, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestBasicDelegation(t *testing.T) {
|
func TestBasicDelegation(t *testing.T) {
|
||||||
mockMinionRegistry := MockMinionRegistry{
|
mockMinionRegistry := registrytest.NewMinionRegistry([]string{"m1", "m2", "m3"})
|
||||||
minions: []string{"m1", "m2", "m3"},
|
healthy := HealthyRegistry{
|
||||||
}
|
delegate: mockMinionRegistry,
|
||||||
healthy := HealthyMinionRegistry{
|
|
||||||
delegate: &mockMinionRegistry,
|
|
||||||
client: alwaysYes{},
|
client: alwaysYes{},
|
||||||
}
|
}
|
||||||
|
|
||||||
list, err := healthy.List()
|
list, err := healthy.List()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
if !reflect.DeepEqual(list, mockMinionRegistry.Minions) {
|
||||||
if !reflect.DeepEqual(list, mockMinionRegistry.minions) {
|
t.Errorf("Expected %v, Got %v", mockMinionRegistry.Minions, list)
|
||||||
t.Errorf("Expected %v, Got %v", mockMinionRegistry.minions, list)
|
|
||||||
}
|
}
|
||||||
err = healthy.Insert("foo")
|
err = healthy.Insert("foo")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ok, err := healthy.Contains("m1")
|
ok, err := healthy.Contains("m1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("Unexpected absence of 'm1'")
|
t.Errorf("Unexpected absence of 'm1'")
|
||||||
}
|
}
|
||||||
|
|
||||||
ok, err = healthy.Contains("m5")
|
ok, err = healthy.Contains("m5")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ok {
|
if ok {
|
||||||
t.Errorf("Unexpected presence of 'm5'")
|
t.Errorf("Unexpected presence of 'm5'")
|
||||||
}
|
}
|
||||||
@@ -91,21 +85,17 @@ func (n *notMinion) Get(url string) (*http.Response, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFiltering(t *testing.T) {
|
func TestFiltering(t *testing.T) {
|
||||||
mockMinionRegistry := MockMinionRegistry{
|
mockMinionRegistry := registrytest.NewMinionRegistry([]string{"m1", "m2", "m3"})
|
||||||
minions: []string{"m1", "m2", "m3"},
|
healthy := HealthyRegistry{
|
||||||
}
|
delegate: mockMinionRegistry,
|
||||||
healthy := HealthyMinionRegistry{
|
|
||||||
delegate: &mockMinionRegistry,
|
|
||||||
client: ¬Minion{minion: "m1"},
|
client: ¬Minion{minion: "m1"},
|
||||||
port: 10250,
|
port: 10250,
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := []string{"m2", "m3"}
|
expected := []string{"m2", "m3"}
|
||||||
list, err := healthy.List()
|
list, err := healthy.List()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(list, expected) {
|
if !reflect.DeepEqual(list, expected) {
|
||||||
t.Errorf("Expected %v, Got %v", expected, list)
|
t.Errorf("Expected %v, Got %v", expected, list)
|
||||||
}
|
}
|
||||||
@@ -113,7 +103,6 @@ func TestFiltering(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ok {
|
if ok {
|
||||||
t.Errorf("Unexpected presence of 'm1'")
|
t.Errorf("Unexpected presence of 'm1'")
|
||||||
}
|
}
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package minion
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -27,7 +27,7 @@ import (
|
|||||||
var ErrDoesNotExist = fmt.Errorf("The requested resource does not exist.")
|
var ErrDoesNotExist = fmt.Errorf("The requested resource does not exist.")
|
||||||
|
|
||||||
// Keep track of a set of minions. Safe for concurrent reading/writing.
|
// Keep track of a set of minions. Safe for concurrent reading/writing.
|
||||||
type MinionRegistry interface {
|
type Registry interface {
|
||||||
List() (currentMinions []string, err error)
|
List() (currentMinions []string, err error)
|
||||||
Insert(minion string) error
|
Insert(minion string) error
|
||||||
Delete(minion string) error
|
Delete(minion string) error
|
||||||
@@ -35,7 +35,7 @@ type MinionRegistry interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize a minion registry with a list of minions.
|
// Initialize a minion registry with a list of minions.
|
||||||
func MakeMinionRegistry(minions []string) MinionRegistry {
|
func NewRegistry(minions []string) Registry {
|
||||||
m := &minionList{
|
m := &minionList{
|
||||||
minions: util.StringSet{},
|
minions: util.StringSet{},
|
||||||
}
|
}
|
||||||
@@ -50,22 +50,10 @@ type minionList struct {
|
|||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *minionList) List() (currentMinions []string, err error) {
|
func (m *minionList) Contains(minion string) (bool, error) {
|
||||||
m.lock.Lock()
|
m.lock.Lock()
|
||||||
defer m.lock.Unlock()
|
defer m.lock.Unlock()
|
||||||
// Convert from map to []string
|
return m.minions.Has(minion), nil
|
||||||
for minion := range m.minions {
|
|
||||||
currentMinions = append(currentMinions, minion)
|
|
||||||
}
|
|
||||||
sort.StringSlice(currentMinions).Sort()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *minionList) Insert(newMinion string) error {
|
|
||||||
m.lock.Lock()
|
|
||||||
defer m.lock.Unlock()
|
|
||||||
m.minions.Insert(newMinion)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *minionList) Delete(minion string) error {
|
func (m *minionList) Delete(minion string) error {
|
||||||
@@ -75,8 +63,19 @@ func (m *minionList) Delete(minion string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *minionList) Contains(minion string) (bool, error) {
|
func (m *minionList) Insert(newMinion string) error {
|
||||||
m.lock.Lock()
|
m.lock.Lock()
|
||||||
defer m.lock.Unlock()
|
defer m.lock.Unlock()
|
||||||
return m.minions.Has(minion), nil
|
m.minions.Insert(newMinion)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *minionList) List() (currentMinions []string, err error) {
|
||||||
|
m.lock.Lock()
|
||||||
|
defer m.lock.Unlock()
|
||||||
|
for minion := range m.minions {
|
||||||
|
currentMinions = append(currentMinions, minion)
|
||||||
|
}
|
||||||
|
sort.StringSlice(currentMinions).Sort()
|
||||||
|
return
|
||||||
}
|
}
|
@@ -14,15 +14,15 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package minion
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMinionRegistry(t *testing.T) {
|
func TestRegistry(t *testing.T) {
|
||||||
m := MakeMinionRegistry([]string{"foo", "bar"})
|
m := NewRegistry([]string{"foo", "bar"})
|
||||||
if has, err := m.Contains("foo"); !has || err != nil {
|
if has, err := m.Contains("foo"); !has || err != nil {
|
||||||
t.Errorf("missing expected object")
|
t.Errorf("missing expected object")
|
||||||
}
|
}
|
||||||
@@ -32,21 +32,18 @@ func TestMinionRegistry(t *testing.T) {
|
|||||||
if has, err := m.Contains("baz"); has || err != nil {
|
if has, err := m.Contains("baz"); has || err != nil {
|
||||||
t.Errorf("has unexpected object")
|
t.Errorf("has unexpected object")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := m.Insert("baz"); err != nil {
|
if err := m.Insert("baz"); err != nil {
|
||||||
t.Errorf("insert failed")
|
t.Errorf("insert failed")
|
||||||
}
|
}
|
||||||
if has, err := m.Contains("baz"); !has || err != nil {
|
if has, err := m.Contains("baz"); !has || err != nil {
|
||||||
t.Errorf("insert didn't actually insert")
|
t.Errorf("insert didn't actually insert")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := m.Delete("bar"); err != nil {
|
if err := m.Delete("bar"); err != nil {
|
||||||
t.Errorf("delete failed")
|
t.Errorf("delete failed")
|
||||||
}
|
}
|
||||||
if has, err := m.Contains("bar"); has || err != nil {
|
if has, err := m.Contains("bar"); has || err != nil {
|
||||||
t.Errorf("delete didn't actually delete")
|
t.Errorf("delete didn't actually delete")
|
||||||
}
|
}
|
||||||
|
|
||||||
list, err := m.List()
|
list, err := m.List()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("got error calling List")
|
t.Errorf("got error calling List")
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package minion
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -24,46 +24,19 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MinionRegistryStorage implements the RESTStorage interface, backed by a MinionRegistry.
|
// RegistryStorage implements the RESTStorage interface, backed by a MinionRegistry.
|
||||||
type MinionRegistryStorage struct {
|
type RegistryStorage struct {
|
||||||
registry MinionRegistry
|
registry Registry
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeMinionRegistryStorage(m MinionRegistry) apiserver.RESTStorage {
|
// NewRegistryStorage returns a new RegistryStorage.
|
||||||
return &MinionRegistryStorage{
|
func NewRegistryStorage(m Registry) apiserver.RESTStorage {
|
||||||
|
return &RegistryStorage{
|
||||||
registry: m,
|
registry: m,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storage *MinionRegistryStorage) toApiMinion(name string) api.Minion {
|
func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
|
||||||
return api.Minion{JSONBase: api.JSONBase{ID: name}}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (storage *MinionRegistryStorage) List(selector labels.Selector) (interface{}, error) {
|
|
||||||
nameList, err := storage.registry.List()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var list api.MinionList
|
|
||||||
for _, name := range nameList {
|
|
||||||
list.Items = append(list.Items, storage.toApiMinion(name))
|
|
||||||
}
|
|
||||||
return list, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (storage *MinionRegistryStorage) Get(id string) (interface{}, error) {
|
|
||||||
exists, err := storage.registry.Contains(id)
|
|
||||||
if !exists {
|
|
||||||
return nil, ErrDoesNotExist
|
|
||||||
}
|
|
||||||
return storage.toApiMinion(id), err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (storage *MinionRegistryStorage) New() interface{} {
|
|
||||||
return &api.Minion{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (storage *MinionRegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
|
|
||||||
minion, ok := obj.(*api.Minion)
|
minion, ok := obj.(*api.Minion)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("not a minion: %#v", obj)
|
return nil, fmt.Errorf("not a minion: %#v", obj)
|
||||||
@@ -72,27 +45,23 @@ func (storage *MinionRegistryStorage) Create(obj interface{}) (<-chan interface{
|
|||||||
return nil, fmt.Errorf("ID should not be empty: %#v", minion)
|
return nil, fmt.Errorf("ID should not be empty: %#v", minion)
|
||||||
}
|
}
|
||||||
return apiserver.MakeAsync(func() (interface{}, error) {
|
return apiserver.MakeAsync(func() (interface{}, error) {
|
||||||
err := storage.registry.Insert(minion.ID)
|
err := rs.registry.Insert(minion.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
contains, err := storage.registry.Contains(minion.ID)
|
contains, err := rs.registry.Contains(minion.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if contains {
|
if contains {
|
||||||
return storage.toApiMinion(minion.ID), nil
|
return rs.toApiMinion(minion.ID), nil
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("unable to add minion %#v", minion)
|
return nil, fmt.Errorf("unable to add minion %#v", minion)
|
||||||
}), nil
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storage *MinionRegistryStorage) Update(minion interface{}) (<-chan interface{}, error) {
|
func (rs *RegistryStorage) Delete(id string) (<-chan interface{}, error) {
|
||||||
return nil, fmt.Errorf("Minions can only be created (inserted) and deleted.")
|
exists, err := rs.registry.Contains(id)
|
||||||
}
|
|
||||||
|
|
||||||
func (storage *MinionRegistryStorage) Delete(id string) (<-chan interface{}, error) {
|
|
||||||
exists, err := storage.registry.Contains(id)
|
|
||||||
if !exists {
|
if !exists {
|
||||||
return nil, ErrDoesNotExist
|
return nil, ErrDoesNotExist
|
||||||
}
|
}
|
||||||
@@ -100,6 +69,38 @@ func (storage *MinionRegistryStorage) Delete(id string) (<-chan interface{}, err
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return apiserver.MakeAsync(func() (interface{}, error) {
|
return apiserver.MakeAsync(func() (interface{}, error) {
|
||||||
return &api.Status{Status: api.StatusSuccess}, storage.registry.Delete(id)
|
return &api.Status{Status: api.StatusSuccess}, rs.registry.Delete(id)
|
||||||
}), nil
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rs *RegistryStorage) Get(id string) (interface{}, error) {
|
||||||
|
exists, err := rs.registry.Contains(id)
|
||||||
|
if !exists {
|
||||||
|
return nil, ErrDoesNotExist
|
||||||
|
}
|
||||||
|
return rs.toApiMinion(id), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *RegistryStorage) List(selector labels.Selector) (interface{}, error) {
|
||||||
|
nameList, err := rs.registry.List()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var list api.MinionList
|
||||||
|
for _, name := range nameList {
|
||||||
|
list.Items = append(list.Items, rs.toApiMinion(name))
|
||||||
|
}
|
||||||
|
return list, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs RegistryStorage) New() interface{} {
|
||||||
|
return &api.Minion{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *RegistryStorage) Update(minion interface{}) (<-chan interface{}, error) {
|
||||||
|
return nil, fmt.Errorf("Minions can only be created (inserted) and deleted.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *RegistryStorage) toApiMinion(name string) api.Minion {
|
||||||
|
return api.Minion{JSONBase: api.JSONBase{ID: name}}
|
||||||
|
}
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package minion
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -25,8 +25,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestMinionRegistryStorage(t *testing.T) {
|
func TestMinionRegistryStorage(t *testing.T) {
|
||||||
m := MakeMinionRegistry([]string{"foo", "bar"})
|
m := NewRegistry([]string{"foo", "bar"})
|
||||||
ms := MakeMinionRegistryStorage(m)
|
ms := NewRegistryStorage(m)
|
||||||
|
|
||||||
if obj, err := ms.Get("foo"); err != nil || obj.(api.Minion).ID != "foo" {
|
if obj, err := ms.Get("foo"); err != nil || obj.(api.Minion).ID != "foo" {
|
||||||
t.Errorf("missing expected object")
|
t.Errorf("missing expected object")
|
@@ -1,127 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 Google Inc. All rights reserved.
|
|
||||||
|
|
||||||
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 registry
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MockPodRegistry struct {
|
|
||||||
err error
|
|
||||||
pod *api.Pod
|
|
||||||
pods []api.Pod
|
|
||||||
sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeMockPodRegistry(pods []api.Pod) *MockPodRegistry {
|
|
||||||
return &MockPodRegistry{
|
|
||||||
pods: pods,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MockPodRegistry) ListPods(selector labels.Selector) ([]api.Pod, error) {
|
|
||||||
registry.Lock()
|
|
||||||
defer registry.Unlock()
|
|
||||||
if registry.err != nil {
|
|
||||||
return registry.pods, registry.err
|
|
||||||
}
|
|
||||||
var filtered []api.Pod
|
|
||||||
for _, pod := range registry.pods {
|
|
||||||
if selector.Matches(labels.Set(pod.Labels)) {
|
|
||||||
filtered = append(filtered, pod)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return filtered, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MockPodRegistry) GetPod(podId string) (*api.Pod, error) {
|
|
||||||
registry.Lock()
|
|
||||||
defer registry.Unlock()
|
|
||||||
return registry.pod, registry.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MockPodRegistry) CreatePod(machine string, pod api.Pod) error {
|
|
||||||
registry.Lock()
|
|
||||||
defer registry.Unlock()
|
|
||||||
return registry.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MockPodRegistry) UpdatePod(pod api.Pod) error {
|
|
||||||
registry.Lock()
|
|
||||||
defer registry.Unlock()
|
|
||||||
registry.pod = &pod
|
|
||||||
return registry.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MockPodRegistry) DeletePod(podId string) error {
|
|
||||||
registry.Lock()
|
|
||||||
defer registry.Unlock()
|
|
||||||
return registry.err
|
|
||||||
}
|
|
||||||
|
|
||||||
type MockMinionRegistry struct {
|
|
||||||
err error
|
|
||||||
minion string
|
|
||||||
minions []string
|
|
||||||
sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeMockMinionRegistry(minions []string) *MockMinionRegistry {
|
|
||||||
return &MockMinionRegistry{
|
|
||||||
minions: minions,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MockMinionRegistry) List() ([]string, error) {
|
|
||||||
registry.Lock()
|
|
||||||
defer registry.Unlock()
|
|
||||||
return registry.minions, registry.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MockMinionRegistry) Insert(minion string) error {
|
|
||||||
registry.Lock()
|
|
||||||
defer registry.Unlock()
|
|
||||||
registry.minion = minion
|
|
||||||
return registry.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MockMinionRegistry) Contains(minion string) (bool, error) {
|
|
||||||
registry.Lock()
|
|
||||||
defer registry.Unlock()
|
|
||||||
for _, name := range registry.minions {
|
|
||||||
if name == minion {
|
|
||||||
return true, registry.err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false, registry.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (registry *MockMinionRegistry) Delete(minion string) error {
|
|
||||||
registry.Lock()
|
|
||||||
defer registry.Unlock()
|
|
||||||
var newList []string
|
|
||||||
for _, name := range registry.minions {
|
|
||||||
if name != minion {
|
|
||||||
newList = append(newList, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
registry.minions = newList
|
|
||||||
return registry.err
|
|
||||||
}
|
|
36
pkg/registry/pod/registry.go
Normal file
36
pkg/registry/pod/registry.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
|
||||||
|
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 pod
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Registry is an interface implemented by things that know how to store Pod objects.
|
||||||
|
type Registry interface {
|
||||||
|
// ListPods obtains a list of pods that match selector.
|
||||||
|
ListPods(selector labels.Selector) ([]api.Pod, error)
|
||||||
|
// Get a specific pod
|
||||||
|
GetPod(podID string) (*api.Pod, error)
|
||||||
|
// Create a pod based on a specification, schedule it onto a specific machine.
|
||||||
|
CreatePod(machine string, pod api.Pod) error
|
||||||
|
// Update an existing pod
|
||||||
|
UpdatePod(pod api.Pod) error
|
||||||
|
// Delete an existing pod
|
||||||
|
DeletePod(podID string) error
|
||||||
|
}
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package pod
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -22,77 +22,130 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.google.com/p/go-uuid/uuid"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/scheduler"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/scheduler"
|
||||||
|
|
||||||
|
"code.google.com/p/go-uuid/uuid"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PodRegistryStorage implements the RESTStorage interface in terms of a PodRegistry
|
// RegistryStorage implements the RESTStorage interface in terms of a PodRegistry
|
||||||
type PodRegistryStorage struct {
|
type RegistryStorage struct {
|
||||||
registry PodRegistry
|
cloudProvider cloudprovider.Interface
|
||||||
podInfoGetter client.PodInfoGetter
|
mu sync.Mutex
|
||||||
podCache client.PodInfoGetter
|
|
||||||
scheduler scheduler.Scheduler
|
|
||||||
minionLister scheduler.MinionLister
|
minionLister scheduler.MinionLister
|
||||||
cloud cloudprovider.Interface
|
podCache client.PodInfoGetter
|
||||||
|
podInfoGetter client.PodInfoGetter
|
||||||
podPollPeriod time.Duration
|
podPollPeriod time.Duration
|
||||||
lock sync.Mutex
|
registry Registry
|
||||||
|
scheduler scheduler.Scheduler
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakePodRegistryStorage makes a RESTStorage object for a pod registry.
|
type RegistryStorageConfig struct {
|
||||||
// Parameters:
|
CloudProvider cloudprovider.Interface
|
||||||
// registry: The pod registry
|
MinionLister scheduler.MinionLister
|
||||||
// podInfoGetter: Source of fresh container info
|
PodCache client.PodInfoGetter
|
||||||
// scheduler: The scheduler for assigning pods to machines
|
PodInfoGetter client.PodInfoGetter
|
||||||
// minionLister: Object which can list available minions for the scheduler
|
Registry Registry
|
||||||
// cloud: Interface to a cloud provider (may be null)
|
Scheduler scheduler.Scheduler
|
||||||
// podCache: Source of cached container info
|
}
|
||||||
func MakePodRegistryStorage(registry PodRegistry,
|
|
||||||
podInfoGetter client.PodInfoGetter,
|
// NewRegistryStorage returns a new RegistryStorage.
|
||||||
scheduler scheduler.Scheduler,
|
func NewRegistryStorage(config *RegistryStorageConfig) apiserver.RESTStorage {
|
||||||
minionLister scheduler.MinionLister,
|
return &RegistryStorage{
|
||||||
cloud cloudprovider.Interface,
|
cloudProvider: config.CloudProvider,
|
||||||
podCache client.PodInfoGetter) apiserver.RESTStorage {
|
minionLister: config.MinionLister,
|
||||||
return &PodRegistryStorage{
|
podCache: config.PodCache,
|
||||||
registry: registry,
|
podInfoGetter: config.PodInfoGetter,
|
||||||
podInfoGetter: podInfoGetter,
|
|
||||||
scheduler: scheduler,
|
|
||||||
minionLister: minionLister,
|
|
||||||
cloud: cloud,
|
|
||||||
podCache: podCache,
|
|
||||||
podPollPeriod: time.Second * 10,
|
podPollPeriod: time.Second * 10,
|
||||||
|
registry: config.Registry,
|
||||||
|
scheduler: config.Scheduler,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storage *PodRegistryStorage) List(selector labels.Selector) (interface{}, error) {
|
func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
|
||||||
|
pod := obj.(*api.Pod)
|
||||||
|
if len(pod.ID) == 0 {
|
||||||
|
pod.ID = uuid.NewUUID().String()
|
||||||
|
}
|
||||||
|
pod.DesiredState.Manifest.ID = pod.ID
|
||||||
|
if errs := api.ValidatePod(pod); len(errs) > 0 {
|
||||||
|
return nil, fmt.Errorf("Validation errors: %v", errs)
|
||||||
|
}
|
||||||
|
return apiserver.MakeAsync(func() (interface{}, error) {
|
||||||
|
if err := rs.scheduleAndCreatePod(*pod); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return rs.waitForPodRunning(*pod)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *RegistryStorage) Delete(id string) (<-chan interface{}, error) {
|
||||||
|
return apiserver.MakeAsync(func() (interface{}, error) {
|
||||||
|
return api.Status{Status: api.StatusSuccess}, rs.registry.DeletePod(id)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *RegistryStorage) Get(id string) (interface{}, error) {
|
||||||
|
pod, err := rs.registry.GetPod(id)
|
||||||
|
if err != nil {
|
||||||
|
return pod, err
|
||||||
|
}
|
||||||
|
if pod == nil {
|
||||||
|
return pod, nil
|
||||||
|
}
|
||||||
|
if rs.podCache != nil || rs.podInfoGetter != nil {
|
||||||
|
rs.fillPodInfo(pod)
|
||||||
|
pod.CurrentState.Status = makePodStatus(pod)
|
||||||
|
}
|
||||||
|
pod.CurrentState.HostIP = getInstanceIP(rs.cloudProvider, pod.CurrentState.Host)
|
||||||
|
return pod, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *RegistryStorage) List(selector labels.Selector) (interface{}, error) {
|
||||||
var result api.PodList
|
var result api.PodList
|
||||||
pods, err := storage.registry.ListPods(selector)
|
pods, err := rs.registry.ListPods(selector)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
result.Items = pods
|
result.Items = pods
|
||||||
for i := range result.Items {
|
for i := range result.Items {
|
||||||
storage.fillPodInfo(&result.Items[i])
|
rs.fillPodInfo(&result.Items[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storage *PodRegistryStorage) fillPodInfo(pod *api.Pod) {
|
func (rs RegistryStorage) New() interface{} {
|
||||||
|
return &api.Pod{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *RegistryStorage) Update(obj interface{}) (<-chan interface{}, error) {
|
||||||
|
pod := obj.(*api.Pod)
|
||||||
|
if errs := api.ValidatePod(pod); len(errs) > 0 {
|
||||||
|
return nil, fmt.Errorf("Validation errors: %v", errs)
|
||||||
|
}
|
||||||
|
return apiserver.MakeAsync(func() (interface{}, error) {
|
||||||
|
if err := rs.registry.UpdatePod(*pod); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return rs.waitForPodRunning(*pod)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *RegistryStorage) fillPodInfo(pod *api.Pod) {
|
||||||
// Get cached info for the list currently.
|
// Get cached info for the list currently.
|
||||||
// TODO: Optionally use fresh info
|
// TODO: Optionally use fresh info
|
||||||
if storage.podCache != nil {
|
if rs.podCache != nil {
|
||||||
info, err := storage.podCache.GetPodInfo(pod.CurrentState.Host, pod.ID)
|
info, err := rs.podCache.GetPodInfo(pod.CurrentState.Host, pod.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != client.ErrPodInfoNotAvailable {
|
if err != client.ErrPodInfoNotAvailable {
|
||||||
glog.Errorf("Error getting container info from cache: %#v", err)
|
glog.Errorf("Error getting container info from cache: %#v", err)
|
||||||
}
|
}
|
||||||
if storage.podInfoGetter != nil {
|
if rs.podInfoGetter != nil {
|
||||||
info, err = storage.podInfoGetter.GetPodInfo(pod.CurrentState.Host, pod.ID)
|
info, err = rs.podInfoGetter.GetPodInfo(pod.CurrentState.Host, pod.ID)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != client.ErrPodInfoNotAvailable {
|
if err != client.ErrPodInfoNotAvailable {
|
||||||
@@ -115,37 +168,6 @@ func (storage *PodRegistryStorage) fillPodInfo(pod *api.Pod) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makePodStatus(pod *api.Pod) api.PodStatus {
|
|
||||||
if pod.CurrentState.Info == nil || pod.CurrentState.Host == "" {
|
|
||||||
return api.PodWaiting
|
|
||||||
}
|
|
||||||
running := 0
|
|
||||||
stopped := 0
|
|
||||||
unknown := 0
|
|
||||||
for _, container := range pod.DesiredState.Manifest.Containers {
|
|
||||||
if info, ok := pod.CurrentState.Info[container.Name]; ok {
|
|
||||||
if info.State.Running {
|
|
||||||
running++
|
|
||||||
} else {
|
|
||||||
stopped++
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
unknown++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case running > 0 && stopped == 0 && unknown == 0:
|
|
||||||
return api.PodRunning
|
|
||||||
case running == 0 && stopped > 0 && unknown == 0:
|
|
||||||
return api.PodTerminated
|
|
||||||
case running == 0 && stopped == 0 && unknown > 0:
|
|
||||||
return api.PodWaiting
|
|
||||||
default:
|
|
||||||
return api.PodWaiting
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getInstanceIP(cloud cloudprovider.Interface, host string) string {
|
func getInstanceIP(cloud cloudprovider.Interface, host string) string {
|
||||||
if cloud == nil {
|
if cloud == nil {
|
||||||
return ""
|
return ""
|
||||||
@@ -166,82 +188,50 @@ func getInstanceIP(cloud cloudprovider.Interface, host string) string {
|
|||||||
return addr.String()
|
return addr.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storage *PodRegistryStorage) Get(id string) (interface{}, error) {
|
func makePodStatus(pod *api.Pod) api.PodStatus {
|
||||||
pod, err := storage.registry.GetPod(id)
|
if pod.CurrentState.Info == nil || pod.CurrentState.Host == "" {
|
||||||
if err != nil {
|
return api.PodWaiting
|
||||||
return pod, err
|
|
||||||
}
|
}
|
||||||
if pod == nil {
|
running := 0
|
||||||
return pod, nil
|
stopped := 0
|
||||||
|
unknown := 0
|
||||||
|
for _, container := range pod.DesiredState.Manifest.Containers {
|
||||||
|
if info, ok := pod.CurrentState.Info[container.Name]; ok {
|
||||||
|
if info.State.Running {
|
||||||
|
running++
|
||||||
|
} else {
|
||||||
|
stopped++
|
||||||
}
|
}
|
||||||
if storage.podCache != nil || storage.podInfoGetter != nil {
|
} else {
|
||||||
storage.fillPodInfo(pod)
|
unknown++
|
||||||
pod.CurrentState.Status = makePodStatus(pod)
|
}
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case running > 0 && stopped == 0 && unknown == 0:
|
||||||
|
return api.PodRunning
|
||||||
|
case running == 0 && stopped > 0 && unknown == 0:
|
||||||
|
return api.PodTerminated
|
||||||
|
case running == 0 && stopped == 0 && unknown > 0:
|
||||||
|
return api.PodWaiting
|
||||||
|
default:
|
||||||
|
return api.PodWaiting
|
||||||
}
|
}
|
||||||
pod.CurrentState.HostIP = getInstanceIP(storage.cloud, pod.CurrentState.Host)
|
|
||||||
|
|
||||||
return pod, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storage *PodRegistryStorage) Delete(id string) (<-chan interface{}, error) {
|
func (rs *RegistryStorage) scheduleAndCreatePod(pod api.Pod) error {
|
||||||
return apiserver.MakeAsync(func() (interface{}, error) {
|
rs.mu.Lock()
|
||||||
return &api.Status{Status: api.StatusSuccess}, storage.registry.DeletePod(id)
|
defer rs.mu.Unlock()
|
||||||
}), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (storage *PodRegistryStorage) New() interface{} {
|
|
||||||
return &api.Pod{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (storage *PodRegistryStorage) scheduleAndCreatePod(pod api.Pod) error {
|
|
||||||
storage.lock.Lock()
|
|
||||||
defer storage.lock.Unlock()
|
|
||||||
// TODO(lavalamp): Separate scheduler more cleanly.
|
// TODO(lavalamp): Separate scheduler more cleanly.
|
||||||
machine, err := storage.scheduler.Schedule(pod, storage.minionLister)
|
machine, err := rs.scheduler.Schedule(pod, rs.minionLister)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return storage.registry.CreatePod(machine, pod)
|
return rs.registry.CreatePod(machine, pod)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storage *PodRegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
|
func (rs *RegistryStorage) waitForPodRunning(pod api.Pod) (interface{}, error) {
|
||||||
pod := obj.(*api.Pod)
|
|
||||||
if len(pod.ID) == 0 {
|
|
||||||
pod.ID = uuid.NewUUID().String()
|
|
||||||
}
|
|
||||||
pod.DesiredState.Manifest.ID = pod.ID
|
|
||||||
|
|
||||||
if errs := api.ValidatePod(pod); len(errs) > 0 {
|
|
||||||
return nil, fmt.Errorf("Validation errors: %v", errs)
|
|
||||||
}
|
|
||||||
|
|
||||||
return apiserver.MakeAsync(func() (interface{}, error) {
|
|
||||||
err := storage.scheduleAndCreatePod(*pod)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return storage.waitForPodRunning(*pod)
|
|
||||||
}), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (storage *PodRegistryStorage) Update(obj interface{}) (<-chan interface{}, error) {
|
|
||||||
pod := obj.(*api.Pod)
|
|
||||||
if errs := api.ValidatePod(pod); len(errs) > 0 {
|
|
||||||
return nil, fmt.Errorf("Validation errors: %v", errs)
|
|
||||||
}
|
|
||||||
return apiserver.MakeAsync(func() (interface{}, error) {
|
|
||||||
err := storage.registry.UpdatePod(*pod)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return storage.waitForPodRunning(*pod)
|
|
||||||
}), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (storage *PodRegistryStorage) waitForPodRunning(pod api.Pod) (interface{}, error) {
|
|
||||||
for {
|
for {
|
||||||
podObj, err := storage.Get(pod.ID)
|
podObj, err := rs.Get(pod.ID)
|
||||||
|
|
||||||
if err != nil || podObj == nil {
|
if err != nil || podObj == nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -254,7 +244,7 @@ func (storage *PodRegistryStorage) waitForPodRunning(pod api.Pod) (interface{},
|
|||||||
case api.PodRunning, api.PodTerminated:
|
case api.PodRunning, api.PodTerminated:
|
||||||
return pod, nil
|
return pod, nil
|
||||||
default:
|
default:
|
||||||
time.Sleep(storage.podPollPeriod)
|
time.Sleep(rs.podPollPeriod)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pod, nil
|
return pod, nil
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package pod
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -25,7 +25,10 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/minion"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/scheduler"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/scheduler"
|
||||||
|
|
||||||
"github.com/fsouza/go-dockerclient"
|
"github.com/fsouza/go-dockerclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -52,12 +55,12 @@ func expectPod(t *testing.T, ch <-chan interface{}) (*api.Pod, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCreatePodRegistryError(t *testing.T) {
|
func TestCreatePodRegistryError(t *testing.T) {
|
||||||
mockRegistry := &MockPodRegistry{
|
podRegistry := ®istrytest.PodRegistry{
|
||||||
err: fmt.Errorf("test error"),
|
Err: fmt.Errorf("test error"),
|
||||||
}
|
}
|
||||||
storage := PodRegistryStorage{
|
storage := RegistryStorage{
|
||||||
scheduler: &MockScheduler{},
|
scheduler: ®istrytest.Scheduler{},
|
||||||
registry: mockRegistry,
|
registry: podRegistry,
|
||||||
}
|
}
|
||||||
desiredState := api.PodState{
|
desiredState := api.PodState{
|
||||||
Manifest: api.ContainerManifest{
|
Manifest: api.ContainerManifest{
|
||||||
@@ -69,25 +72,14 @@ func TestCreatePodRegistryError(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Expected %#v, Got %#v", nil, err)
|
t.Errorf("Expected %#v, Got %#v", nil, err)
|
||||||
}
|
}
|
||||||
expectApiStatusError(t, ch, mockRegistry.err.Error())
|
expectApiStatusError(t, ch, podRegistry.Err.Error())
|
||||||
}
|
|
||||||
|
|
||||||
type MockScheduler struct {
|
|
||||||
err error
|
|
||||||
pod api.Pod
|
|
||||||
machine string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MockScheduler) Schedule(pod api.Pod, lister scheduler.MinionLister) (string, error) {
|
|
||||||
m.pod = pod
|
|
||||||
return m.machine, m.err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreatePodSchedulerError(t *testing.T) {
|
func TestCreatePodSchedulerError(t *testing.T) {
|
||||||
mockScheduler := MockScheduler{
|
mockScheduler := registrytest.Scheduler{
|
||||||
err: fmt.Errorf("test error"),
|
Err: fmt.Errorf("test error"),
|
||||||
}
|
}
|
||||||
storage := PodRegistryStorage{
|
storage := RegistryStorage{
|
||||||
scheduler: &mockScheduler,
|
scheduler: &mockScheduler,
|
||||||
}
|
}
|
||||||
desiredState := api.PodState{
|
desiredState := api.PodState{
|
||||||
@@ -100,26 +92,15 @@ func TestCreatePodSchedulerError(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Expected %#v, Got %#v", nil, err)
|
t.Errorf("Expected %#v, Got %#v", nil, err)
|
||||||
}
|
}
|
||||||
expectApiStatusError(t, ch, mockScheduler.err.Error())
|
expectApiStatusError(t, ch, mockScheduler.Err.Error())
|
||||||
}
|
|
||||||
|
|
||||||
type MockPodStorageRegistry struct {
|
|
||||||
MockPodRegistry
|
|
||||||
machine string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *MockPodStorageRegistry) CreatePod(machine string, pod api.Pod) error {
|
|
||||||
r.MockPodRegistry.pod = &pod
|
|
||||||
r.machine = machine
|
|
||||||
return r.MockPodRegistry.err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreatePodSetsIds(t *testing.T) {
|
func TestCreatePodSetsIds(t *testing.T) {
|
||||||
mockRegistry := &MockPodStorageRegistry{
|
mockRegistry := ®istrytest.PodRegistryStorage{
|
||||||
MockPodRegistry: MockPodRegistry{err: fmt.Errorf("test error")},
|
PodRegistry: registrytest.PodRegistry{Err: fmt.Errorf("test error")},
|
||||||
}
|
}
|
||||||
storage := PodRegistryStorage{
|
storage := RegistryStorage{
|
||||||
scheduler: &MockScheduler{machine: "test"},
|
scheduler: ®istrytest.Scheduler{Machine: "test"},
|
||||||
registry: mockRegistry,
|
registry: mockRegistry,
|
||||||
}
|
}
|
||||||
desiredState := api.PodState{
|
desiredState := api.PodState{
|
||||||
@@ -132,26 +113,26 @@ func TestCreatePodSetsIds(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Expected %#v, Got %#v", nil, err)
|
t.Errorf("Expected %#v, Got %#v", nil, err)
|
||||||
}
|
}
|
||||||
expectApiStatusError(t, ch, mockRegistry.err.Error())
|
expectApiStatusError(t, ch, mockRegistry.Err.Error())
|
||||||
|
|
||||||
if len(mockRegistry.MockPodRegistry.pod.ID) == 0 {
|
if len(mockRegistry.PodRegistry.Pod.ID) == 0 {
|
||||||
t.Errorf("Expected pod ID to be set, Got %#v", pod)
|
t.Errorf("Expected pod ID to be set, Got %#v", pod)
|
||||||
}
|
}
|
||||||
if mockRegistry.MockPodRegistry.pod.DesiredState.Manifest.ID != mockRegistry.MockPodRegistry.pod.ID {
|
if mockRegistry.PodRegistry.Pod.DesiredState.Manifest.ID != mockRegistry.PodRegistry.Pod.ID {
|
||||||
t.Errorf("Expected manifest ID to be equal to pod ID, Got %#v", pod)
|
t.Errorf("Expected manifest ID to be equal to pod ID, Got %#v", pod)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestListPodsError(t *testing.T) {
|
func TestListPodsError(t *testing.T) {
|
||||||
mockRegistry := MockPodRegistry{
|
mockRegistry := registrytest.PodRegistry{
|
||||||
err: fmt.Errorf("test error"),
|
Err: fmt.Errorf("test error"),
|
||||||
}
|
}
|
||||||
storage := PodRegistryStorage{
|
storage := RegistryStorage{
|
||||||
registry: &mockRegistry,
|
registry: &mockRegistry,
|
||||||
}
|
}
|
||||||
pods, err := storage.List(labels.Everything())
|
pods, err := storage.List(labels.Everything())
|
||||||
if err != mockRegistry.err {
|
if err != mockRegistry.Err {
|
||||||
t.Errorf("Expected %#v, Got %#v", mockRegistry.err, err)
|
t.Errorf("Expected %#v, Got %#v", mockRegistry.Err, err)
|
||||||
}
|
}
|
||||||
if len(pods.(api.PodList).Items) != 0 {
|
if len(pods.(api.PodList).Items) != 0 {
|
||||||
t.Errorf("Unexpected non-zero pod list: %#v", pods)
|
t.Errorf("Unexpected non-zero pod list: %#v", pods)
|
||||||
@@ -159,8 +140,8 @@ func TestListPodsError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestListEmptyPodList(t *testing.T) {
|
func TestListEmptyPodList(t *testing.T) {
|
||||||
mockRegistry := MockPodRegistry{}
|
mockRegistry := registrytest.PodRegistry{}
|
||||||
storage := PodRegistryStorage{
|
storage := RegistryStorage{
|
||||||
registry: &mockRegistry,
|
registry: &mockRegistry,
|
||||||
}
|
}
|
||||||
pods, err := storage.List(labels.Everything())
|
pods, err := storage.List(labels.Everything())
|
||||||
@@ -174,8 +155,8 @@ func TestListEmptyPodList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestListPodList(t *testing.T) {
|
func TestListPodList(t *testing.T) {
|
||||||
mockRegistry := MockPodRegistry{
|
mockRegistry := registrytest.PodRegistry{
|
||||||
pods: []api.Pod{
|
Pods: []api.Pod{
|
||||||
{
|
{
|
||||||
JSONBase: api.JSONBase{
|
JSONBase: api.JSONBase{
|
||||||
ID: "foo",
|
ID: "foo",
|
||||||
@@ -188,7 +169,7 @@ func TestListPodList(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
storage := PodRegistryStorage{
|
storage := RegistryStorage{
|
||||||
registry: &mockRegistry,
|
registry: &mockRegistry,
|
||||||
}
|
}
|
||||||
podsObj, err := storage.List(labels.Everything())
|
podsObj, err := storage.List(labels.Everything())
|
||||||
@@ -209,8 +190,8 @@ func TestListPodList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPodDecode(t *testing.T) {
|
func TestPodDecode(t *testing.T) {
|
||||||
mockRegistry := MockPodRegistry{}
|
mockRegistry := registrytest.PodRegistry{}
|
||||||
storage := PodRegistryStorage{
|
storage := RegistryStorage{
|
||||||
registry: &mockRegistry,
|
registry: &mockRegistry,
|
||||||
}
|
}
|
||||||
expected := &api.Pod{
|
expected := &api.Pod{
|
||||||
@@ -234,12 +215,12 @@ func TestPodDecode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGetPod(t *testing.T) {
|
func TestGetPod(t *testing.T) {
|
||||||
mockRegistry := MockPodRegistry{
|
mockRegistry := registrytest.PodRegistry{
|
||||||
pod: &api.Pod{
|
Pod: &api.Pod{
|
||||||
JSONBase: api.JSONBase{ID: "foo"},
|
JSONBase: api.JSONBase{ID: "foo"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
storage := PodRegistryStorage{
|
storage := RegistryStorage{
|
||||||
registry: &mockRegistry,
|
registry: &mockRegistry,
|
||||||
}
|
}
|
||||||
obj, err := storage.Get("foo")
|
obj, err := storage.Get("foo")
|
||||||
@@ -248,21 +229,21 @@ func TestGetPod(t *testing.T) {
|
|||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(*mockRegistry.pod, *pod) {
|
if !reflect.DeepEqual(*mockRegistry.Pod, *pod) {
|
||||||
t.Errorf("Unexpected pod. Expected %#v, Got %#v", *mockRegistry.pod, *pod)
|
t.Errorf("Unexpected pod. Expected %#v, Got %#v", *mockRegistry.Pod, *pod)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetPodCloud(t *testing.T) {
|
func TestGetPodCloud(t *testing.T) {
|
||||||
fakeCloud := &cloudprovider.FakeCloud{}
|
fakeCloud := &cloudprovider.FakeCloud{}
|
||||||
mockRegistry := MockPodRegistry{
|
mockRegistry := registrytest.PodRegistry{
|
||||||
pod: &api.Pod{
|
Pod: &api.Pod{
|
||||||
JSONBase: api.JSONBase{ID: "foo"},
|
JSONBase: api.JSONBase{ID: "foo"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
storage := PodRegistryStorage{
|
storage := RegistryStorage{
|
||||||
registry: &mockRegistry,
|
registry: &mockRegistry,
|
||||||
cloud: fakeCloud,
|
cloudProvider: fakeCloud,
|
||||||
}
|
}
|
||||||
obj, err := storage.Get("foo")
|
obj, err := storage.Get("foo")
|
||||||
pod := obj.(*api.Pod)
|
pod := obj.(*api.Pod)
|
||||||
@@ -270,8 +251,8 @@ func TestGetPodCloud(t *testing.T) {
|
|||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(*mockRegistry.pod, *pod) {
|
if !reflect.DeepEqual(*mockRegistry.Pod, *pod) {
|
||||||
t.Errorf("Unexpected pod. Expected %#v, Got %#v", *mockRegistry.pod, *pod)
|
t.Errorf("Unexpected pod. Expected %#v, Got %#v", *mockRegistry.Pod, *pod)
|
||||||
}
|
}
|
||||||
if len(fakeCloud.Calls) != 1 || fakeCloud.Calls[0] != "ip-address" {
|
if len(fakeCloud.Calls) != 1 || fakeCloud.Calls[0] != "ip-address" {
|
||||||
t.Errorf("Unexpected calls: %#v", fakeCloud.Calls)
|
t.Errorf("Unexpected calls: %#v", fakeCloud.Calls)
|
||||||
@@ -373,11 +354,11 @@ func TestMakePodStatus(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPodStorageValidatesCreate(t *testing.T) {
|
func TestPodStorageValidatesCreate(t *testing.T) {
|
||||||
mockRegistry := &MockPodStorageRegistry{
|
mockRegistry := ®istrytest.PodRegistryStorage{
|
||||||
MockPodRegistry: MockPodRegistry{err: fmt.Errorf("test error")},
|
PodRegistry: registrytest.PodRegistry{Err: fmt.Errorf("test error")},
|
||||||
}
|
}
|
||||||
storage := PodRegistryStorage{
|
storage := RegistryStorage{
|
||||||
scheduler: &MockScheduler{machine: "test"},
|
scheduler: ®istrytest.Scheduler{Machine: "test"},
|
||||||
registry: mockRegistry,
|
registry: mockRegistry,
|
||||||
}
|
}
|
||||||
pod := &api.Pod{}
|
pod := &api.Pod{}
|
||||||
@@ -391,11 +372,11 @@ func TestPodStorageValidatesCreate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPodStorageValidatesUpdate(t *testing.T) {
|
func TestPodStorageValidatesUpdate(t *testing.T) {
|
||||||
mockRegistry := &MockPodStorageRegistry{
|
mockRegistry := ®istrytest.PodRegistryStorage{
|
||||||
MockPodRegistry: MockPodRegistry{err: fmt.Errorf("test error")},
|
PodRegistry: registrytest.PodRegistry{Err: fmt.Errorf("test error")},
|
||||||
}
|
}
|
||||||
storage := PodRegistryStorage{
|
storage := RegistryStorage{
|
||||||
scheduler: &MockScheduler{machine: "test"},
|
scheduler: ®istrytest.Scheduler{Machine: "test"},
|
||||||
registry: mockRegistry,
|
registry: mockRegistry,
|
||||||
}
|
}
|
||||||
pod := &api.Pod{}
|
pod := &api.Pod{}
|
||||||
@@ -409,19 +390,19 @@ func TestPodStorageValidatesUpdate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCreatePod(t *testing.T) {
|
func TestCreatePod(t *testing.T) {
|
||||||
mockRegistry := MockPodRegistry{
|
mockRegistry := registrytest.PodRegistry{
|
||||||
pod: &api.Pod{
|
Pod: &api.Pod{
|
||||||
JSONBase: api.JSONBase{ID: "foo"},
|
JSONBase: api.JSONBase{ID: "foo"},
|
||||||
CurrentState: api.PodState{
|
CurrentState: api.PodState{
|
||||||
Host: "machine",
|
Host: "machine",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
storage := PodRegistryStorage{
|
storage := RegistryStorage{
|
||||||
registry: &mockRegistry,
|
registry: &mockRegistry,
|
||||||
podPollPeriod: time.Millisecond * 100,
|
podPollPeriod: time.Millisecond * 100,
|
||||||
scheduler: scheduler.MakeRoundRobinScheduler(),
|
scheduler: scheduler.MakeRoundRobinScheduler(),
|
||||||
minionLister: MakeMinionRegistry([]string{"machine"}),
|
minionLister: minion.NewRegistry([]string{"machine"}),
|
||||||
}
|
}
|
||||||
desiredState := api.PodState{
|
desiredState := api.PodState{
|
||||||
Manifest: api.ContainerManifest{
|
Manifest: api.ContainerManifest{
|
||||||
@@ -479,18 +460,14 @@ func TestFillPodInfo(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
storage := PodRegistryStorage{
|
storage := RegistryStorage{
|
||||||
podCache: &fakeGetter,
|
podCache: &fakeGetter,
|
||||||
}
|
}
|
||||||
|
|
||||||
pod := api.Pod{}
|
pod := api.Pod{}
|
||||||
|
|
||||||
storage.fillPodInfo(&pod)
|
storage.fillPodInfo(&pod)
|
||||||
|
|
||||||
if !reflect.DeepEqual(fakeGetter.info, pod.CurrentState.Info) {
|
if !reflect.DeepEqual(fakeGetter.info, pod.CurrentState.Info) {
|
||||||
t.Errorf("Expected: %#v, Got %#v", fakeGetter.info, pod.CurrentState.Info)
|
t.Errorf("Expected: %#v, Got %#v", fakeGetter.info, pod.CurrentState.Info)
|
||||||
}
|
}
|
||||||
|
|
||||||
if pod.CurrentState.PodIP != expectedIP {
|
if pod.CurrentState.PodIP != expectedIP {
|
||||||
t.Errorf("Expected %s, Got %s", expectedIP, pod.CurrentState.PodIP)
|
t.Errorf("Expected %s, Got %s", expectedIP, pod.CurrentState.PodIP)
|
||||||
}
|
}
|
||||||
@@ -506,18 +483,14 @@ func TestFillPodInfoNoData(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
storage := PodRegistryStorage{
|
storage := RegistryStorage{
|
||||||
podCache: &fakeGetter,
|
podCache: &fakeGetter,
|
||||||
}
|
}
|
||||||
|
|
||||||
pod := api.Pod{}
|
pod := api.Pod{}
|
||||||
|
|
||||||
storage.fillPodInfo(&pod)
|
storage.fillPodInfo(&pod)
|
||||||
|
|
||||||
if !reflect.DeepEqual(fakeGetter.info, pod.CurrentState.Info) {
|
if !reflect.DeepEqual(fakeGetter.info, pod.CurrentState.Info) {
|
||||||
t.Errorf("Expected %#v, Got %#v", fakeGetter.info, pod.CurrentState.Info)
|
t.Errorf("Expected %#v, Got %#v", fakeGetter.info, pod.CurrentState.Info)
|
||||||
}
|
}
|
||||||
|
|
||||||
if pod.CurrentState.PodIP != expectedIP {
|
if pod.CurrentState.PodIP != expectedIP {
|
||||||
t.Errorf("Expected %s, Got %s", expectedIP, pod.CurrentState.PodIP)
|
t.Errorf("Expected %s, Got %s", expectedIP, pod.CurrentState.PodIP)
|
||||||
}
|
}
|
53
pkg/registry/registrytest/controller.go
Normal file
53
pkg/registry/registrytest/controller.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
|
||||||
|
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 registrytest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: Why do we have this AND MemoryRegistry?
|
||||||
|
type ControllerRegistry struct {
|
||||||
|
Err error
|
||||||
|
Controllers []api.ReplicationController
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ControllerRegistry) ListControllers() ([]api.ReplicationController, error) {
|
||||||
|
return r.Controllers, r.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ControllerRegistry) GetController(ID string) (*api.ReplicationController, error) {
|
||||||
|
return &api.ReplicationController{}, r.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ControllerRegistry) CreateController(controller api.ReplicationController) error {
|
||||||
|
return r.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ControllerRegistry) UpdateController(controller api.ReplicationController) error {
|
||||||
|
return r.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ControllerRegistry) DeleteController(ID string) error {
|
||||||
|
return r.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ControllerRegistry) WatchControllers(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
|
||||||
|
return nil, r.Err
|
||||||
|
}
|
69
pkg/registry/registrytest/minion.go
Normal file
69
pkg/registry/registrytest/minion.go
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
|
||||||
|
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 registrytest
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
|
type MinionRegistry struct {
|
||||||
|
Err error
|
||||||
|
Minion string
|
||||||
|
Minions []string
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMinionRegistry(minions []string) *MinionRegistry {
|
||||||
|
return &MinionRegistry{
|
||||||
|
Minions: minions,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MinionRegistry) List() ([]string, error) {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
return r.Minions, r.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MinionRegistry) Insert(minion string) error {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
r.Minion = minion
|
||||||
|
return r.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MinionRegistry) Contains(minion string) (bool, error) {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
for _, name := range r.Minions {
|
||||||
|
if name == minion {
|
||||||
|
return true, r.Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, r.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MinionRegistry) Delete(minion string) error {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
var newList []string
|
||||||
|
for _, name := range r.Minions {
|
||||||
|
if name != minion {
|
||||||
|
newList = append(newList, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r.Minions = newList
|
||||||
|
return r.Err
|
||||||
|
}
|
77
pkg/registry/registrytest/pod.go
Normal file
77
pkg/registry/registrytest/pod.go
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
|
||||||
|
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 registrytest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PodRegistry struct {
|
||||||
|
Err error
|
||||||
|
Pod *api.Pod
|
||||||
|
Pods []api.Pod
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPodRegistry(pods []api.Pod) *PodRegistry {
|
||||||
|
return &PodRegistry{
|
||||||
|
Pods: pods,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *PodRegistry) ListPods(selector labels.Selector) ([]api.Pod, error) {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
if r.Err != nil {
|
||||||
|
return r.Pods, r.Err
|
||||||
|
}
|
||||||
|
var filtered []api.Pod
|
||||||
|
for _, pod := range r.Pods {
|
||||||
|
if selector.Matches(labels.Set(pod.Labels)) {
|
||||||
|
filtered = append(filtered, pod)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filtered, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *PodRegistry) GetPod(podId string) (*api.Pod, error) {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
return r.Pod, r.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *PodRegistry) CreatePod(machine string, pod api.Pod) error {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
return r.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *PodRegistry) UpdatePod(pod api.Pod) error {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
r.Pod = &pod
|
||||||
|
return r.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *PodRegistry) DeletePod(podId string) error {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
return r.Err
|
||||||
|
}
|
30
pkg/registry/registrytest/pod_storage.go
Normal file
30
pkg/registry/registrytest/pod_storage.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
|
||||||
|
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 registrytest
|
||||||
|
|
||||||
|
import "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
|
||||||
|
type PodRegistryStorage struct {
|
||||||
|
PodRegistry
|
||||||
|
machine string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *PodRegistryStorage) CreatePod(machine string, pod api.Pod) error {
|
||||||
|
rs.PodRegistry.Pod = &pod
|
||||||
|
rs.machine = machine
|
||||||
|
return rs.PodRegistry.Err
|
||||||
|
}
|
33
pkg/registry/registrytest/schedular.go
Normal file
33
pkg/registry/registrytest/schedular.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
|
||||||
|
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 registrytest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/scheduler"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Scheduler struct {
|
||||||
|
Err error
|
||||||
|
Pod api.Pod
|
||||||
|
Machine string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Scheduler) Schedule(pod api.Pod, lister scheduler.MinionLister) (string, error) {
|
||||||
|
s.Pod = pod
|
||||||
|
return s.Machine, s.Err
|
||||||
|
}
|
@@ -14,39 +14,39 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package registrytest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MockServiceRegistry struct {
|
type ServiceRegistry struct {
|
||||||
list api.ServiceList
|
List api.ServiceList
|
||||||
err error
|
Err error
|
||||||
endpoints api.Endpoints
|
Endpoints api.Endpoints
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockServiceRegistry) ListServices() (api.ServiceList, error) {
|
func (r *ServiceRegistry) ListServices() (api.ServiceList, error) {
|
||||||
return m.list, m.err
|
return r.List, r.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockServiceRegistry) CreateService(svc api.Service) error {
|
func (r *ServiceRegistry) CreateService(svc api.Service) error {
|
||||||
return m.err
|
return r.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockServiceRegistry) GetService(name string) (*api.Service, error) {
|
func (r *ServiceRegistry) GetService(name string) (*api.Service, error) {
|
||||||
return nil, m.err
|
return nil, r.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockServiceRegistry) DeleteService(name string) error {
|
func (r *ServiceRegistry) DeleteService(name string) error {
|
||||||
return m.err
|
return r.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockServiceRegistry) UpdateService(svc api.Service) error {
|
func (r *ServiceRegistry) UpdateService(svc api.Service) error {
|
||||||
return m.err
|
return r.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockServiceRegistry) UpdateEndpoints(e api.Endpoints) error {
|
func (r *ServiceRegistry) UpdateEndpoints(e api.Endpoints) error {
|
||||||
m.endpoints = e
|
r.Endpoints = e
|
||||||
return m.err
|
return r.Err
|
||||||
}
|
}
|
31
pkg/registry/service/registry.go
Normal file
31
pkg/registry/service/registry.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
|
||||||
|
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 service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Registry is an interface for things that know how to store services.
|
||||||
|
type Registry interface {
|
||||||
|
ListServices() (api.ServiceList, error)
|
||||||
|
CreateService(svc api.Service) error
|
||||||
|
GetService(name string) (*api.Service, error)
|
||||||
|
DeleteService(name string) error
|
||||||
|
UpdateService(svc api.Service) error
|
||||||
|
UpdateEndpoints(e api.Endpoints) error
|
||||||
|
}
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -25,25 +25,168 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/minion"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ServiceRegistryStorage adapts a service registry into apiserver's RESTStorage model.
|
// RegistryStorage adapts a service registry into apiserver's RESTStorage model.
|
||||||
type ServiceRegistryStorage struct {
|
type RegistryStorage struct {
|
||||||
registry ServiceRegistry
|
registry Registry
|
||||||
cloud cloudprovider.Interface
|
cloud cloudprovider.Interface
|
||||||
machines MinionRegistry
|
machines minion.Registry
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeServiceRegistryStorage makes a new ServiceRegistryStorage.
|
// NewRegistryStorage returns a new RegistryStorage.
|
||||||
func MakeServiceRegistryStorage(registry ServiceRegistry, cloud cloudprovider.Interface, machines MinionRegistry) apiserver.RESTStorage {
|
func NewRegistryStorage(registry Registry, cloud cloudprovider.Interface, machines minion.Registry) apiserver.RESTStorage {
|
||||||
return &ServiceRegistryStorage{
|
return &RegistryStorage{
|
||||||
registry: registry,
|
registry: registry,
|
||||||
cloud: cloud,
|
cloud: cloud,
|
||||||
machines: machines,
|
machines: machines,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
|
||||||
|
srv := obj.(*api.Service)
|
||||||
|
if errs := api.ValidateService(srv); len(errs) > 0 {
|
||||||
|
return nil, fmt.Errorf("Validation errors: %v", errs)
|
||||||
|
}
|
||||||
|
return apiserver.MakeAsync(func() (interface{}, error) {
|
||||||
|
// TODO: Consider moving this to a rectification loop, so that we make/remove external load balancers
|
||||||
|
// correctly no matter what http operations happen.
|
||||||
|
if srv.CreateExternalLoadBalancer {
|
||||||
|
if rs.cloud == nil {
|
||||||
|
return nil, fmt.Errorf("requested an external service, but no cloud provider supplied.")
|
||||||
|
}
|
||||||
|
balancer, ok := rs.cloud.TCPLoadBalancer()
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("The cloud provider does not support external TCP load balancers.")
|
||||||
|
}
|
||||||
|
zones, ok := rs.cloud.Zones()
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("The cloud provider does not support zone enumeration.")
|
||||||
|
}
|
||||||
|
hosts, err := rs.machines.List()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
zone, err := zones.GetZone()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = balancer.CreateTCPLoadBalancer(srv.ID, zone.Region, srv.Port, hosts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO actually wait for the object to be fully created here.
|
||||||
|
err := rs.registry.CreateService(*srv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return rs.registry.GetService(srv.ID)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *RegistryStorage) Delete(id string) (<-chan interface{}, error) {
|
||||||
|
service, err := rs.registry.GetService(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return apiserver.MakeAsync(func() (interface{}, error) {
|
||||||
|
rs.deleteExternalLoadBalancer(service)
|
||||||
|
return api.Status{Status: api.StatusSuccess}, rs.registry.DeleteService(id)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *RegistryStorage) Get(id string) (interface{}, error) {
|
||||||
|
s, err := rs.registry.GetService(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return s, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *RegistryStorage) List(selector labels.Selector) (interface{}, error) {
|
||||||
|
list, err := rs.registry.ListServices()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var filtered []api.Service
|
||||||
|
for _, service := range list.Items {
|
||||||
|
if selector.Matches(labels.Set(service.Labels)) {
|
||||||
|
filtered = append(filtered, service)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list.Items = filtered
|
||||||
|
return list, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs RegistryStorage) New() interface{} {
|
||||||
|
return &api.Service{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetServiceEnvironmentVariables populates a list of environment variables that are use
|
||||||
|
// in the container environment to get access to services.
|
||||||
|
func GetServiceEnvironmentVariables(registry Registry, machine string) ([]api.EnvVar, error) {
|
||||||
|
var result []api.EnvVar
|
||||||
|
services, err := registry.ListServices()
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
for _, service := range services.Items {
|
||||||
|
name := strings.ToUpper(service.ID) + "_SERVICE_PORT"
|
||||||
|
value := strconv.Itoa(service.Port)
|
||||||
|
result = append(result, api.EnvVar{Name: name, Value: value})
|
||||||
|
result = append(result, makeLinkVariables(service, machine)...)
|
||||||
|
}
|
||||||
|
result = append(result, api.EnvVar{Name: "SERVICE_HOST", Value: machine})
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *RegistryStorage) Update(obj interface{}) (<-chan interface{}, error) {
|
||||||
|
srv := obj.(*api.Service)
|
||||||
|
if srv.ID == "" {
|
||||||
|
return nil, fmt.Errorf("ID should not be empty: %#v", srv)
|
||||||
|
}
|
||||||
|
if errs := api.ValidateService(srv); len(errs) > 0 {
|
||||||
|
return nil, fmt.Errorf("Validation errors: %v", errs)
|
||||||
|
}
|
||||||
|
return apiserver.MakeAsync(func() (interface{}, error) {
|
||||||
|
// TODO: check to see if external load balancer status changed
|
||||||
|
err := rs.registry.UpdateService(*srv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return rs.registry.GetService(srv.ID)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *RegistryStorage) deleteExternalLoadBalancer(service *api.Service) error {
|
||||||
|
if !service.CreateExternalLoadBalancer || rs.cloud == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
zones, ok := rs.cloud.Zones()
|
||||||
|
if !ok {
|
||||||
|
// We failed to get zone enumerator.
|
||||||
|
// As this should have failed when we tried in "create" too,
|
||||||
|
// assume external load balancer was never created.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
balancer, ok := rs.cloud.TCPLoadBalancer()
|
||||||
|
if !ok {
|
||||||
|
// See comment above.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
zone, err := zones.GetZone()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := balancer.DeleteTCPLoadBalancer(service.JSONBase.ID, zone.Region); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func makeLinkVariables(service api.Service, machine string) []api.EnvVar {
|
func makeLinkVariables(service api.Service, machine string) []api.EnvVar {
|
||||||
prefix := strings.ToUpper(service.ID)
|
prefix := strings.ToUpper(service.ID)
|
||||||
var port string
|
var port string
|
||||||
@@ -76,150 +219,3 @@ func makeLinkVariables(service api.Service, machine string) []api.EnvVar {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetServiceEnvironmentVariables populates a list of environment variables that are use
|
|
||||||
// in the container environment to get access to services.
|
|
||||||
func GetServiceEnvironmentVariables(registry ServiceRegistry, machine string) ([]api.EnvVar, error) {
|
|
||||||
var result []api.EnvVar
|
|
||||||
services, err := registry.ListServices()
|
|
||||||
if err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
for _, service := range services.Items {
|
|
||||||
name := strings.ToUpper(service.ID) + "_SERVICE_PORT"
|
|
||||||
value := strconv.Itoa(service.Port)
|
|
||||||
result = append(result, api.EnvVar{Name: name, Value: value})
|
|
||||||
result = append(result, makeLinkVariables(service, machine)...)
|
|
||||||
}
|
|
||||||
result = append(result, api.EnvVar{Name: "SERVICE_HOST", Value: machine})
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sr *ServiceRegistryStorage) List(selector labels.Selector) (interface{}, error) {
|
|
||||||
list, err := sr.registry.ListServices()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var filtered []api.Service
|
|
||||||
for _, service := range list.Items {
|
|
||||||
if selector.Matches(labels.Set(service.Labels)) {
|
|
||||||
filtered = append(filtered, service)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list.Items = filtered
|
|
||||||
return list, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sr *ServiceRegistryStorage) Get(id string) (interface{}, error) {
|
|
||||||
service, err := sr.registry.GetService(id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return service, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sr *ServiceRegistryStorage) deleteExternalLoadBalancer(service *api.Service) error {
|
|
||||||
if !service.CreateExternalLoadBalancer || sr.cloud == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
zones, ok := sr.cloud.Zones()
|
|
||||||
if !ok {
|
|
||||||
// We failed to get zone enumerator.
|
|
||||||
// As this should have failed when we tried in "create" too,
|
|
||||||
// assume external load balancer was never created.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
balancer, ok := sr.cloud.TCPLoadBalancer()
|
|
||||||
if !ok {
|
|
||||||
// See comment above.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
zone, err := zones.GetZone()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := balancer.DeleteTCPLoadBalancer(service.JSONBase.ID, zone.Region); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sr *ServiceRegistryStorage) Delete(id string) (<-chan interface{}, error) {
|
|
||||||
service, err := sr.registry.GetService(id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return apiserver.MakeAsync(func() (interface{}, error) {
|
|
||||||
sr.deleteExternalLoadBalancer(service)
|
|
||||||
return &api.Status{Status: api.StatusSuccess}, sr.registry.DeleteService(id)
|
|
||||||
}), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sr *ServiceRegistryStorage) New() interface{} {
|
|
||||||
return &api.Service{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sr *ServiceRegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
|
|
||||||
srv := obj.(*api.Service)
|
|
||||||
if errs := api.ValidateService(srv); len(errs) > 0 {
|
|
||||||
return nil, fmt.Errorf("Validation errors: %v", errs)
|
|
||||||
}
|
|
||||||
return apiserver.MakeAsync(func() (interface{}, error) {
|
|
||||||
// TODO: Consider moving this to a rectification loop, so that we make/remove external load balancers
|
|
||||||
// correctly no matter what http operations happen.
|
|
||||||
if srv.CreateExternalLoadBalancer {
|
|
||||||
if sr.cloud == nil {
|
|
||||||
return nil, fmt.Errorf("requested an external service, but no cloud provider supplied.")
|
|
||||||
}
|
|
||||||
balancer, ok := sr.cloud.TCPLoadBalancer()
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("The cloud provider does not support external TCP load balancers.")
|
|
||||||
}
|
|
||||||
zones, ok := sr.cloud.Zones()
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("The cloud provider does not support zone enumeration.")
|
|
||||||
}
|
|
||||||
hosts, err := sr.machines.List()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
zone, err := zones.GetZone()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = balancer.CreateTCPLoadBalancer(srv.ID, zone.Region, srv.Port, hosts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO actually wait for the object to be fully created here.
|
|
||||||
err := sr.registry.CreateService(*srv)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return sr.registry.GetService(srv.ID)
|
|
||||||
}), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sr *ServiceRegistryStorage) Update(obj interface{}) (<-chan interface{}, error) {
|
|
||||||
srv := obj.(*api.Service)
|
|
||||||
if srv.ID == "" {
|
|
||||||
return nil, fmt.Errorf("ID should not be empty: %#v", srv)
|
|
||||||
}
|
|
||||||
if errs := api.ValidateService(srv); len(errs) > 0 {
|
|
||||||
return nil, fmt.Errorf("Validation errors: %v", errs)
|
|
||||||
}
|
|
||||||
return apiserver.MakeAsync(func() (interface{}, error) {
|
|
||||||
// TODO: check to see if external load balancer status changed
|
|
||||||
err := sr.registry.UpdateService(*srv)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return sr.registry.GetService(srv.ID)
|
|
||||||
}), nil
|
|
||||||
}
|
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package registry
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -23,40 +23,37 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/memory"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/minion"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestServiceRegistry(t *testing.T) {
|
func TestRegistry(t *testing.T) {
|
||||||
memory := MakeMemoryRegistry()
|
registry := memory.NewRegistry()
|
||||||
fakeCloud := &cloudprovider.FakeCloud{}
|
fakeCloud := &cloudprovider.FakeCloud{}
|
||||||
machines := []string{"foo", "bar", "baz"}
|
machines := []string{"foo", "bar", "baz"}
|
||||||
|
storage := NewRegistryStorage(registry, fakeCloud, minion.NewRegistry(machines))
|
||||||
storage := MakeServiceRegistryStorage(memory, fakeCloud, MakeMinionRegistry(machines))
|
|
||||||
|
|
||||||
svc := &api.Service{
|
svc := &api.Service{
|
||||||
JSONBase: api.JSONBase{ID: "foo"},
|
JSONBase: api.JSONBase{ID: "foo"},
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
}
|
}
|
||||||
c, _ := storage.Create(svc)
|
c, _ := storage.Create(svc)
|
||||||
<-c
|
<-c
|
||||||
|
|
||||||
if len(fakeCloud.Calls) != 0 {
|
if len(fakeCloud.Calls) != 0 {
|
||||||
t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls)
|
t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls)
|
||||||
}
|
}
|
||||||
srv, err := memory.GetService(svc.ID)
|
srv, err := registry.GetService(svc.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if srv == nil {
|
if srv == nil {
|
||||||
t.Errorf("Failed to find service: %s", svc.ID)
|
t.Errorf("Failed to find service: %s", svc.ID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServiceStorageValidatesCreate(t *testing.T) {
|
func TestServiceStorageValidatesCreate(t *testing.T) {
|
||||||
memory := MakeMemoryRegistry()
|
registry := memory.NewRegistry()
|
||||||
storage := MakeServiceRegistryStorage(memory, nil, nil)
|
storage := NewRegistryStorage(registry, nil, nil)
|
||||||
|
|
||||||
failureCases := map[string]api.Service{
|
failureCases := map[string]api.Service{
|
||||||
"empty ID": {
|
"empty ID": {
|
||||||
JSONBase: api.JSONBase{ID: ""},
|
JSONBase: api.JSONBase{ID: ""},
|
||||||
@@ -79,13 +76,12 @@ func TestServiceStorageValidatesCreate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestServiceStorageValidatesUpdate(t *testing.T) {
|
func TestServiceStorageValidatesUpdate(t *testing.T) {
|
||||||
memory := MakeMemoryRegistry()
|
registry := memory.NewRegistry()
|
||||||
memory.CreateService(api.Service{
|
registry.CreateService(api.Service{
|
||||||
JSONBase: api.JSONBase{ID: "foo"},
|
JSONBase: api.JSONBase{ID: "foo"},
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
})
|
})
|
||||||
storage := MakeServiceRegistryStorage(memory, nil, nil)
|
storage := NewRegistryStorage(registry, nil, nil)
|
||||||
|
|
||||||
failureCases := map[string]api.Service{
|
failureCases := map[string]api.Service{
|
||||||
"empty ID": {
|
"empty ID": {
|
||||||
JSONBase: api.JSONBase{ID: ""},
|
JSONBase: api.JSONBase{ID: ""},
|
||||||
@@ -108,12 +104,10 @@ func TestServiceStorageValidatesUpdate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestServiceRegistryExternalService(t *testing.T) {
|
func TestServiceRegistryExternalService(t *testing.T) {
|
||||||
memory := MakeMemoryRegistry()
|
registry := memory.NewRegistry()
|
||||||
fakeCloud := &cloudprovider.FakeCloud{}
|
fakeCloud := &cloudprovider.FakeCloud{}
|
||||||
machines := []string{"foo", "bar", "baz"}
|
machines := []string{"foo", "bar", "baz"}
|
||||||
|
storage := NewRegistryStorage(registry, fakeCloud, minion.NewRegistry(machines))
|
||||||
storage := MakeServiceRegistryStorage(memory, fakeCloud, MakeMinionRegistry(machines))
|
|
||||||
|
|
||||||
svc := &api.Service{
|
svc := &api.Service{
|
||||||
JSONBase: api.JSONBase{ID: "foo"},
|
JSONBase: api.JSONBase{ID: "foo"},
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
@@ -121,29 +115,25 @@ func TestServiceRegistryExternalService(t *testing.T) {
|
|||||||
}
|
}
|
||||||
c, _ := storage.Create(svc)
|
c, _ := storage.Create(svc)
|
||||||
<-c
|
<-c
|
||||||
|
|
||||||
if len(fakeCloud.Calls) != 2 || fakeCloud.Calls[0] != "get-zone" || fakeCloud.Calls[1] != "create" {
|
if len(fakeCloud.Calls) != 2 || fakeCloud.Calls[0] != "get-zone" || fakeCloud.Calls[1] != "create" {
|
||||||
t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls)
|
t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls)
|
||||||
}
|
}
|
||||||
srv, err := memory.GetService(svc.ID)
|
srv, err := registry.GetService(svc.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if srv == nil {
|
if srv == nil {
|
||||||
t.Errorf("Failed to find service: %s", svc.ID)
|
t.Errorf("Failed to find service: %s", svc.ID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServiceRegistryExternalServiceError(t *testing.T) {
|
func TestServiceRegistryExternalServiceError(t *testing.T) {
|
||||||
memory := MakeMemoryRegistry()
|
registry := memory.NewRegistry()
|
||||||
fakeCloud := &cloudprovider.FakeCloud{
|
fakeCloud := &cloudprovider.FakeCloud{
|
||||||
Err: fmt.Errorf("test error"),
|
Err: fmt.Errorf("test error"),
|
||||||
}
|
}
|
||||||
machines := []string{"foo", "bar", "baz"}
|
machines := []string{"foo", "bar", "baz"}
|
||||||
|
storage := NewRegistryStorage(registry, fakeCloud, minion.NewRegistry(machines))
|
||||||
storage := MakeServiceRegistryStorage(memory, fakeCloud, MakeMinionRegistry(machines))
|
|
||||||
|
|
||||||
svc := &api.Service{
|
svc := &api.Service{
|
||||||
JSONBase: api.JSONBase{ID: "foo"},
|
JSONBase: api.JSONBase{ID: "foo"},
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
@@ -151,75 +141,66 @@ func TestServiceRegistryExternalServiceError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
c, _ := storage.Create(svc)
|
c, _ := storage.Create(svc)
|
||||||
<-c
|
<-c
|
||||||
|
|
||||||
if len(fakeCloud.Calls) != 1 || fakeCloud.Calls[0] != "get-zone" {
|
if len(fakeCloud.Calls) != 1 || fakeCloud.Calls[0] != "get-zone" {
|
||||||
t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls)
|
t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls)
|
||||||
}
|
}
|
||||||
srv, err := memory.GetService("foo")
|
srv, err := registry.GetService("foo")
|
||||||
if !apiserver.IsNotFound(err) {
|
if !apiserver.IsNotFound(err) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("memory.GetService(%q) failed with %v; expected failure with not found error", svc.ID, err)
|
t.Errorf("registry.GetService(%q) failed with %v; expected failure with not found error", svc.ID, err)
|
||||||
} else {
|
} else {
|
||||||
t.Errorf("memory.GetService(%q) = %v; expected failure with not found error", svc.ID, srv)
|
t.Errorf("registry.GetService(%q) = %v; expected failure with not found error", svc.ID, srv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServiceRegistryDelete(t *testing.T) {
|
func TestServiceRegistryDelete(t *testing.T) {
|
||||||
memory := MakeMemoryRegistry()
|
registry := memory.NewRegistry()
|
||||||
fakeCloud := &cloudprovider.FakeCloud{}
|
fakeCloud := &cloudprovider.FakeCloud{}
|
||||||
machines := []string{"foo", "bar", "baz"}
|
machines := []string{"foo", "bar", "baz"}
|
||||||
|
storage := NewRegistryStorage(registry, fakeCloud, minion.NewRegistry(machines))
|
||||||
storage := MakeServiceRegistryStorage(memory, fakeCloud, MakeMinionRegistry(machines))
|
|
||||||
|
|
||||||
svc := api.Service{
|
svc := api.Service{
|
||||||
JSONBase: api.JSONBase{ID: "foo"},
|
JSONBase: api.JSONBase{ID: "foo"},
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
}
|
}
|
||||||
memory.CreateService(svc)
|
registry.CreateService(svc)
|
||||||
|
|
||||||
c, _ := storage.Delete(svc.ID)
|
c, _ := storage.Delete(svc.ID)
|
||||||
<-c
|
<-c
|
||||||
|
|
||||||
if len(fakeCloud.Calls) != 0 {
|
if len(fakeCloud.Calls) != 0 {
|
||||||
t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls)
|
t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls)
|
||||||
}
|
}
|
||||||
srv, err := memory.GetService(svc.ID)
|
srv, err := registry.GetService(svc.ID)
|
||||||
if !apiserver.IsNotFound(err) {
|
if !apiserver.IsNotFound(err) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("memory.GetService(%q) failed with %v; expected failure with not found error", svc.ID, err)
|
t.Errorf("registry.GetService(%q) failed with %v; expected failure with not found error", svc.ID, err)
|
||||||
} else {
|
} else {
|
||||||
t.Errorf("memory.GetService(%q) = %v; expected failure with not found error", svc.ID, srv)
|
t.Errorf("registry.GetService(%q) = %v; expected failure with not found error", svc.ID, srv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServiceRegistryDeleteExternal(t *testing.T) {
|
func TestServiceRegistryDeleteExternal(t *testing.T) {
|
||||||
memory := MakeMemoryRegistry()
|
registry := memory.NewRegistry()
|
||||||
fakeCloud := &cloudprovider.FakeCloud{}
|
fakeCloud := &cloudprovider.FakeCloud{}
|
||||||
machines := []string{"foo", "bar", "baz"}
|
machines := []string{"foo", "bar", "baz"}
|
||||||
|
storage := NewRegistryStorage(registry, fakeCloud, minion.NewRegistry(machines))
|
||||||
storage := MakeServiceRegistryStorage(memory, fakeCloud, MakeMinionRegistry(machines))
|
|
||||||
|
|
||||||
svc := api.Service{
|
svc := api.Service{
|
||||||
JSONBase: api.JSONBase{ID: "foo"},
|
JSONBase: api.JSONBase{ID: "foo"},
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
CreateExternalLoadBalancer: true,
|
CreateExternalLoadBalancer: true,
|
||||||
}
|
}
|
||||||
memory.CreateService(svc)
|
registry.CreateService(svc)
|
||||||
|
|
||||||
c, _ := storage.Delete(svc.ID)
|
c, _ := storage.Delete(svc.ID)
|
||||||
<-c
|
<-c
|
||||||
|
|
||||||
if len(fakeCloud.Calls) != 2 || fakeCloud.Calls[0] != "get-zone" || fakeCloud.Calls[1] != "delete" {
|
if len(fakeCloud.Calls) != 2 || fakeCloud.Calls[0] != "get-zone" || fakeCloud.Calls[1] != "delete" {
|
||||||
t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls)
|
t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls)
|
||||||
}
|
}
|
||||||
srv, err := memory.GetService(svc.ID)
|
srv, err := registry.GetService(svc.ID)
|
||||||
if !apiserver.IsNotFound(err) {
|
if !apiserver.IsNotFound(err) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("memory.GetService(%q) failed with %v; expected failure with not found error", svc.ID, err)
|
t.Errorf("registry.GetService(%q) failed with %v; expected failure with not found error", svc.ID, err)
|
||||||
} else {
|
} else {
|
||||||
t.Errorf("memory.GetService(%q) = %v; expected failure with not found error", svc.ID, srv)
|
t.Errorf("registry.GetService(%q) = %v; expected failure with not found error", svc.ID, srv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user