git mv Ingress ingress
This commit is contained in:
parent
34b949c134
commit
3da4e74e5a
2185 changed files with 754743 additions and 0 deletions
127
controllers/gce/instances/fakes.go
Normal file
127
controllers/gce/instances/fakes.go
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors 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 instances
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
compute "google.golang.org/api/compute/v1"
|
||||
"k8s.io/contrib/ingress/controllers/gce/utils"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
)
|
||||
|
||||
// NewFakeInstanceGroups creates a new FakeInstanceGroups.
|
||||
func NewFakeInstanceGroups(nodes sets.String) *FakeInstanceGroups {
|
||||
return &FakeInstanceGroups{
|
||||
instances: nodes,
|
||||
listResult: getInstanceList(nodes),
|
||||
namer: utils.Namer{},
|
||||
}
|
||||
}
|
||||
|
||||
// InstanceGroup fakes
|
||||
|
||||
// FakeInstanceGroups fakes out the instance groups api.
|
||||
type FakeInstanceGroups struct {
|
||||
instances sets.String
|
||||
instanceGroups []*compute.InstanceGroup
|
||||
Ports []int64
|
||||
getResult *compute.InstanceGroup
|
||||
listResult *compute.InstanceGroupsListInstances
|
||||
calls []int
|
||||
namer utils.Namer
|
||||
}
|
||||
|
||||
// GetInstanceGroup fakes getting an instance group from the cloud.
|
||||
func (f *FakeInstanceGroups) GetInstanceGroup(name, zone string) (*compute.InstanceGroup, error) {
|
||||
f.calls = append(f.calls, utils.Get)
|
||||
for _, ig := range f.instanceGroups {
|
||||
if ig.Name == name {
|
||||
return ig, nil
|
||||
}
|
||||
}
|
||||
// TODO: Return googleapi 404 error
|
||||
return nil, fmt.Errorf("Instance group %v not found", name)
|
||||
}
|
||||
|
||||
// CreateInstanceGroup fakes instance group creation.
|
||||
func (f *FakeInstanceGroups) CreateInstanceGroup(name, zone string) (*compute.InstanceGroup, error) {
|
||||
newGroup := &compute.InstanceGroup{Name: name, SelfLink: name}
|
||||
f.instanceGroups = append(f.instanceGroups, newGroup)
|
||||
return newGroup, nil
|
||||
}
|
||||
|
||||
// DeleteInstanceGroup fakes instance group deletion.
|
||||
func (f *FakeInstanceGroups) DeleteInstanceGroup(name, zone string) error {
|
||||
newGroups := []*compute.InstanceGroup{}
|
||||
found := false
|
||||
for _, ig := range f.instanceGroups {
|
||||
if ig.Name == name {
|
||||
found = true
|
||||
continue
|
||||
}
|
||||
newGroups = append(newGroups, ig)
|
||||
}
|
||||
if !found {
|
||||
return fmt.Errorf("Instance Group %v not found", name)
|
||||
}
|
||||
f.instanceGroups = newGroups
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListInstancesInInstanceGroup fakes listing instances in an instance group.
|
||||
func (f *FakeInstanceGroups) ListInstancesInInstanceGroup(name, zone string, state string) (*compute.InstanceGroupsListInstances, error) {
|
||||
return f.listResult, nil
|
||||
}
|
||||
|
||||
// AddInstancesToInstanceGroup fakes adding instances to an instance group.
|
||||
func (f *FakeInstanceGroups) AddInstancesToInstanceGroup(name, zone string, instanceNames []string) error {
|
||||
f.calls = append(f.calls, utils.AddInstances)
|
||||
f.instances.Insert(instanceNames...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveInstancesFromInstanceGroup fakes removing instances from an instance group.
|
||||
func (f *FakeInstanceGroups) RemoveInstancesFromInstanceGroup(name, zone string, instanceNames []string) error {
|
||||
f.calls = append(f.calls, utils.RemoveInstances)
|
||||
f.instances.Delete(instanceNames...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddPortToInstanceGroup fakes adding ports to an Instance Group.
|
||||
func (f *FakeInstanceGroups) AddPortToInstanceGroup(ig *compute.InstanceGroup, port int64) (*compute.NamedPort, error) {
|
||||
f.Ports = append(f.Ports, port)
|
||||
return &compute.NamedPort{Name: f.namer.BeName(port), Port: port}, nil
|
||||
}
|
||||
|
||||
// getInstanceList returns an instance list based on the given names.
|
||||
// The names cannot contain a '.', the real gce api validates against this.
|
||||
func getInstanceList(nodeNames sets.String) *compute.InstanceGroupsListInstances {
|
||||
instanceNames := nodeNames.List()
|
||||
computeInstances := []*compute.InstanceWithNamedPorts{}
|
||||
for _, name := range instanceNames {
|
||||
instanceLink := fmt.Sprintf(
|
||||
"https://www.googleapis.com/compute/v1/projects/%s/zones/%s/instances/%s",
|
||||
"project", "zone", name)
|
||||
computeInstances = append(
|
||||
computeInstances, &compute.InstanceWithNamedPorts{
|
||||
Instance: instanceLink})
|
||||
}
|
||||
return &compute.InstanceGroupsListInstances{
|
||||
Items: computeInstances,
|
||||
}
|
||||
}
|
||||
165
controllers/gce/instances/instances.go
Normal file
165
controllers/gce/instances/instances.go
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors 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 instances
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
compute "google.golang.org/api/compute/v1"
|
||||
"k8s.io/contrib/ingress/controllers/gce/storage"
|
||||
"k8s.io/contrib/ingress/controllers/gce/utils"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
const (
|
||||
// State string required by gce library to list all instances.
|
||||
allInstances = "ALL"
|
||||
)
|
||||
|
||||
// Instances implements NodePool.
|
||||
type Instances struct {
|
||||
cloud InstanceGroups
|
||||
zone string
|
||||
snapshotter storage.Snapshotter
|
||||
}
|
||||
|
||||
// NewNodePool creates a new node pool.
|
||||
// - cloud: implements InstanceGroups, used to sync Kubernetes nodes with
|
||||
// members of the cloud InstanceGroup.
|
||||
func NewNodePool(cloud InstanceGroups, zone string) NodePool {
|
||||
glog.V(3).Infof("NodePool is only aware of instances in zone %v", zone)
|
||||
return &Instances{cloud, zone, storage.NewInMemoryPool()}
|
||||
}
|
||||
|
||||
// AddInstanceGroup creates or gets an instance group if it doesn't exist
|
||||
// and adds the given port to it.
|
||||
func (i *Instances) AddInstanceGroup(name string, port int64) (*compute.InstanceGroup, *compute.NamedPort, error) {
|
||||
ig, _ := i.Get(name)
|
||||
if ig == nil {
|
||||
glog.Infof("Creating instance group %v", name)
|
||||
var err error
|
||||
ig, err = i.cloud.CreateInstanceGroup(name, i.zone)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
} else {
|
||||
glog.V(3).Infof("Instance group already exists %v", name)
|
||||
}
|
||||
defer i.snapshotter.Add(name, ig)
|
||||
namedPort, err := i.cloud.AddPortToInstanceGroup(ig, port)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return ig, namedPort, nil
|
||||
}
|
||||
|
||||
// DeleteInstanceGroup deletes the given IG by name.
|
||||
func (i *Instances) DeleteInstanceGroup(name string) error {
|
||||
defer i.snapshotter.Delete(name)
|
||||
return i.cloud.DeleteInstanceGroup(name, i.zone)
|
||||
}
|
||||
|
||||
func (i *Instances) list(name string) (sets.String, error) {
|
||||
nodeNames := sets.NewString()
|
||||
instances, err := i.cloud.ListInstancesInInstanceGroup(
|
||||
name, i.zone, allInstances)
|
||||
if err != nil {
|
||||
return nodeNames, err
|
||||
}
|
||||
for _, ins := range instances.Items {
|
||||
// TODO: If round trips weren't so slow one would be inclided
|
||||
// to GetInstance using this url and get the name.
|
||||
parts := strings.Split(ins.Instance, "/")
|
||||
nodeNames.Insert(parts[len(parts)-1])
|
||||
}
|
||||
return nodeNames, nil
|
||||
}
|
||||
|
||||
// Get returns the Instance Group by name.
|
||||
func (i *Instances) Get(name string) (*compute.InstanceGroup, error) {
|
||||
ig, err := i.cloud.GetInstanceGroup(name, i.zone)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i.snapshotter.Add(name, ig)
|
||||
return ig, nil
|
||||
}
|
||||
|
||||
// Add adds the given instances to the Instance Group.
|
||||
func (i *Instances) Add(groupName string, names []string) error {
|
||||
glog.V(3).Infof("Adding nodes %v to %v", names, groupName)
|
||||
return i.cloud.AddInstancesToInstanceGroup(groupName, i.zone, names)
|
||||
}
|
||||
|
||||
// Remove removes the given instances from the Instance Group.
|
||||
func (i *Instances) Remove(groupName string, names []string) error {
|
||||
glog.V(3).Infof("Removing nodes %v from %v", names, groupName)
|
||||
return i.cloud.RemoveInstancesFromInstanceGroup(groupName, i.zone, names)
|
||||
}
|
||||
|
||||
// Sync syncs kubernetes instances with the instances in the instance group.
|
||||
func (i *Instances) Sync(nodes []string) (err error) {
|
||||
glog.V(3).Infof("Syncing nodes %v", nodes)
|
||||
|
||||
defer func() {
|
||||
// The node pool is only responsible for syncing nodes to instance
|
||||
// groups. It never creates/deletes, so if an instance groups is
|
||||
// not found there's nothing it can do about it anyway. Most cases
|
||||
// this will happen because the backend pool has deleted the instance
|
||||
// group, however if it happens because a user deletes the IG by mistake
|
||||
// we should just wait till the backend pool fixes it.
|
||||
if utils.IsHTTPErrorCode(err, http.StatusNotFound) {
|
||||
glog.Infof("Node pool encountered a 404, ignoring: %v", err)
|
||||
err = nil
|
||||
}
|
||||
}()
|
||||
|
||||
pool := i.snapshotter.Snapshot()
|
||||
for name := range pool {
|
||||
gceNodes := sets.NewString()
|
||||
gceNodes, err = i.list(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
kubeNodes := sets.NewString(nodes...)
|
||||
|
||||
// A node deleted via kubernetes could still exist as a gce vm. We don't
|
||||
// want to route requests to it. Similarly, a node added to kubernetes
|
||||
// needs to get added to the instance group so we do route requests to it.
|
||||
|
||||
removeNodes := gceNodes.Difference(kubeNodes).List()
|
||||
addNodes := kubeNodes.Difference(gceNodes).List()
|
||||
if len(removeNodes) != 0 {
|
||||
if err = i.Remove(
|
||||
name, gceNodes.Difference(kubeNodes).List()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(addNodes) != 0 {
|
||||
if err = i.Add(
|
||||
name, kubeNodes.Difference(gceNodes).List()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
75
controllers/gce/instances/instances_test.go
Normal file
75
controllers/gce/instances/instances_test.go
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors 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 instances
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
)
|
||||
|
||||
const defaultZone = "default-zone"
|
||||
|
||||
func TestNodePoolSync(t *testing.T) {
|
||||
f := NewFakeInstanceGroups(sets.NewString(
|
||||
[]string{"n1", "n2"}...))
|
||||
pool := NewNodePool(f, defaultZone)
|
||||
pool.AddInstanceGroup("test", 80)
|
||||
|
||||
// KubeNodes: n1
|
||||
// GCENodes: n1, n2
|
||||
// Remove n2 from the instance group.
|
||||
|
||||
f.calls = []int{}
|
||||
kubeNodes := sets.NewString([]string{"n1"}...)
|
||||
pool.Sync(kubeNodes.List())
|
||||
if f.instances.Len() != kubeNodes.Len() || !kubeNodes.IsSuperset(f.instances) {
|
||||
t.Fatalf("%v != %v", kubeNodes, f.instances)
|
||||
}
|
||||
|
||||
// KubeNodes: n1, n2
|
||||
// GCENodes: n1
|
||||
// Try to add n2 to the instance group.
|
||||
|
||||
f = NewFakeInstanceGroups(sets.NewString([]string{"n1"}...))
|
||||
pool = NewNodePool(f, defaultZone)
|
||||
pool.AddInstanceGroup("test", 80)
|
||||
|
||||
f.calls = []int{}
|
||||
kubeNodes = sets.NewString([]string{"n1", "n2"}...)
|
||||
pool.Sync(kubeNodes.List())
|
||||
if f.instances.Len() != kubeNodes.Len() ||
|
||||
!kubeNodes.IsSuperset(f.instances) {
|
||||
t.Fatalf("%v != %v", kubeNodes, f.instances)
|
||||
}
|
||||
|
||||
// KubeNodes: n1, n2
|
||||
// GCENodes: n1, n2
|
||||
// Do nothing.
|
||||
|
||||
f = NewFakeInstanceGroups(sets.NewString([]string{"n1", "n2"}...))
|
||||
pool = NewNodePool(f, defaultZone)
|
||||
pool.AddInstanceGroup("test", 80)
|
||||
|
||||
f.calls = []int{}
|
||||
kubeNodes = sets.NewString([]string{"n1", "n2"}...)
|
||||
pool.Sync(kubeNodes.List())
|
||||
if len(f.calls) != 0 {
|
||||
t.Fatalf(
|
||||
"Did not expect any calls, got %+v", f.calls)
|
||||
}
|
||||
}
|
||||
47
controllers/gce/instances/interfaces.go
Normal file
47
controllers/gce/instances/interfaces.go
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors 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 instances
|
||||
|
||||
import (
|
||||
compute "google.golang.org/api/compute/v1"
|
||||
)
|
||||
|
||||
// NodePool is an interface to manage a pool of kubernetes nodes synced with vm instances in the cloud
|
||||
// through the InstanceGroups interface.
|
||||
type NodePool interface {
|
||||
AddInstanceGroup(name string, port int64) (*compute.InstanceGroup, *compute.NamedPort, error)
|
||||
DeleteInstanceGroup(name string) error
|
||||
|
||||
// TODO: Refactor for modularity
|
||||
Add(groupName string, nodeNames []string) error
|
||||
Remove(groupName string, nodeNames []string) error
|
||||
Sync(nodeNames []string) error
|
||||
Get(name string) (*compute.InstanceGroup, error)
|
||||
}
|
||||
|
||||
// InstanceGroups is an interface for managing gce instances groups, and the instances therein.
|
||||
type InstanceGroups interface {
|
||||
GetInstanceGroup(name, zone string) (*compute.InstanceGroup, error)
|
||||
CreateInstanceGroup(name, zone string) (*compute.InstanceGroup, error)
|
||||
DeleteInstanceGroup(name, zone string) error
|
||||
|
||||
// TODO: Refactor for modulatiry.
|
||||
ListInstancesInInstanceGroup(name, zone string, state string) (*compute.InstanceGroupsListInstances, error)
|
||||
AddInstancesToInstanceGroup(name, zone string, instanceNames []string) error
|
||||
RemoveInstancesFromInstanceGroup(name, zone string, instanceName []string) error
|
||||
AddPortToInstanceGroup(ig *compute.InstanceGroup, port int64) (*compute.NamedPort, error)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue