mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 11:48:15 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			291 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			291 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
Copyright 2015 The Kubernetes Authors.
 | 
						|
 | 
						|
Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
you may not use this file except in compliance with the License.
 | 
						|
You may obtain a copy of the License at
 | 
						|
 | 
						|
    http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 | 
						|
Unless required by applicable law or agreed to in writing, software
 | 
						|
distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
See the License for the specific language governing permissions and
 | 
						|
limitations under the License.
 | 
						|
*/
 | 
						|
 | 
						|
package e2e
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"io/ioutil"
 | 
						|
	"net/http"
 | 
						|
 | 
						|
	"k8s.io/kubernetes/pkg/api"
 | 
						|
	"k8s.io/kubernetes/pkg/api/v1"
 | 
						|
	clientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
 | 
						|
	"k8s.io/kubernetes/pkg/labels"
 | 
						|
	"k8s.io/kubernetes/pkg/runtime"
 | 
						|
	"k8s.io/kubernetes/pkg/util/wait"
 | 
						|
	utilyaml "k8s.io/kubernetes/pkg/util/yaml"
 | 
						|
	"k8s.io/kubernetes/test/e2e/framework"
 | 
						|
	"k8s.io/kubernetes/test/e2e/generated"
 | 
						|
 | 
						|
	. "github.com/onsi/ginkgo"
 | 
						|
	. "github.com/onsi/gomega"
 | 
						|
)
 | 
						|
 | 
						|
// getLoadBalancerControllers returns a list of LBCtesters.
 | 
						|
func getLoadBalancerControllers(client clientset.Interface) []LBCTester {
 | 
						|
	return []LBCTester{
 | 
						|
		&haproxyControllerTester{
 | 
						|
			name:   "haproxy",
 | 
						|
			cfg:    "test/e2e/testing-manifests/serviceloadbalancer/haproxyrc.yaml",
 | 
						|
			client: client,
 | 
						|
		},
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// getIngManagers returns a list of ingManagers.
 | 
						|
func getIngManagers(client clientset.Interface) []*ingManager {
 | 
						|
	return []*ingManager{
 | 
						|
		{
 | 
						|
			name:        "netexec",
 | 
						|
			rcCfgPaths:  []string{"test/e2e/testing-manifests/serviceloadbalancer/netexecrc.yaml"},
 | 
						|
			svcCfgPaths: []string{"test/e2e/testing-manifests/serviceloadbalancer/netexecsvc.yaml"},
 | 
						|
			svcNames:    []string{},
 | 
						|
			client:      client,
 | 
						|
		},
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// LBCTester is an interface used to test loadbalancer controllers.
 | 
						|
type LBCTester interface {
 | 
						|
	// start starts the loadbalancer controller in the given namespace
 | 
						|
	start(namespace string) error
 | 
						|
	// lookup returns the address (ip/hostname) associated with ingressKey
 | 
						|
	lookup(ingressKey string) string
 | 
						|
	// stop stops the loadbalancer controller
 | 
						|
	stop() error
 | 
						|
	// name returns the name of the loadbalancer
 | 
						|
	getName() string
 | 
						|
}
 | 
						|
 | 
						|
// haproxyControllerTester implements LBCTester for bare metal haproxy LBs.
 | 
						|
type haproxyControllerTester struct {
 | 
						|
	client      clientset.Interface
 | 
						|
	cfg         string
 | 
						|
	rcName      string
 | 
						|
	rcNamespace string
 | 
						|
	name        string
 | 
						|
	address     []string
 | 
						|
}
 | 
						|
 | 
						|
func (h *haproxyControllerTester) getName() string {
 | 
						|
	return h.name
 | 
						|
}
 | 
						|
 | 
						|
func (h *haproxyControllerTester) start(namespace string) (err error) {
 | 
						|
 | 
						|
	// Create a replication controller with the given configuration.
 | 
						|
	rc := rcFromManifest(h.cfg)
 | 
						|
	rc.Namespace = namespace
 | 
						|
	rc.Spec.Template.Labels["name"] = rc.Name
 | 
						|
 | 
						|
	// Add the --namespace arg.
 | 
						|
	// TODO: Remove this when we have proper namespace support.
 | 
						|
	for i, c := range rc.Spec.Template.Spec.Containers {
 | 
						|
		rc.Spec.Template.Spec.Containers[i].Args = append(
 | 
						|
			c.Args, fmt.Sprintf("--namespace=%v", namespace))
 | 
						|
		framework.Logf("Container args %+v", rc.Spec.Template.Spec.Containers[i].Args)
 | 
						|
	}
 | 
						|
 | 
						|
	rc, err = h.client.Core().ReplicationControllers(rc.Namespace).Create(rc)
 | 
						|
	if err != nil {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	if err = framework.WaitForControlledPodsRunning(h.client, namespace, rc.Name, api.Kind("ReplicationController")); err != nil {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	h.rcName = rc.Name
 | 
						|
	h.rcNamespace = rc.Namespace
 | 
						|
 | 
						|
	// Find the pods of the rc we just created.
 | 
						|
	labelSelector := labels.SelectorFromSet(
 | 
						|
		labels.Set(map[string]string{"name": h.rcName}))
 | 
						|
	options := v1.ListOptions{LabelSelector: labelSelector.String()}
 | 
						|
	pods, err := h.client.Core().Pods(h.rcNamespace).List(options)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	// Find the external addresses of the nodes the pods are running on.
 | 
						|
	for _, p := range pods.Items {
 | 
						|
		wait.Poll(pollInterval, framework.ServiceRespondingTimeout, func() (bool, error) {
 | 
						|
			address, err := framework.GetHostExternalAddress(h.client, &p)
 | 
						|
			if err != nil {
 | 
						|
				framework.Logf("%v", err)
 | 
						|
				return false, nil
 | 
						|
			}
 | 
						|
			h.address = append(h.address, address)
 | 
						|
			return true, nil
 | 
						|
		})
 | 
						|
	}
 | 
						|
	if len(h.address) == 0 {
 | 
						|
		return fmt.Errorf("No external ips found for loadbalancer %v", h.getName())
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (h *haproxyControllerTester) stop() error {
 | 
						|
	return h.client.Core().ReplicationControllers(h.rcNamespace).Delete(h.rcName, nil)
 | 
						|
}
 | 
						|
 | 
						|
func (h *haproxyControllerTester) lookup(ingressKey string) string {
 | 
						|
	// The address of a service is the address of the lb/servicename, currently.
 | 
						|
	return fmt.Sprintf("http://%v/%v", h.address[0], ingressKey)
 | 
						|
}
 | 
						|
 | 
						|
// ingManager starts an rc and the associated service.
 | 
						|
type ingManager struct {
 | 
						|
	rcCfgPaths  []string
 | 
						|
	svcCfgPaths []string
 | 
						|
	ingCfgPath  string
 | 
						|
	name        string
 | 
						|
	namespace   string
 | 
						|
	client      clientset.Interface
 | 
						|
	svcNames    []string
 | 
						|
}
 | 
						|
 | 
						|
func (s *ingManager) getName() string {
 | 
						|
	return s.name
 | 
						|
}
 | 
						|
 | 
						|
func (s *ingManager) start(namespace string) (err error) {
 | 
						|
	// Create rcs
 | 
						|
	for _, rcPath := range s.rcCfgPaths {
 | 
						|
		rc := rcFromManifest(rcPath)
 | 
						|
		rc.Namespace = namespace
 | 
						|
		rc.Spec.Template.Labels["name"] = rc.Name
 | 
						|
		rc, err = s.client.Core().ReplicationControllers(rc.Namespace).Create(rc)
 | 
						|
		if err != nil {
 | 
						|
			return
 | 
						|
		}
 | 
						|
		if err = framework.WaitForControlledPodsRunning(s.client, rc.Namespace, rc.Name, api.Kind("ReplicationController")); err != nil {
 | 
						|
			return
 | 
						|
		}
 | 
						|
	}
 | 
						|
	// Create services.
 | 
						|
	// Note that it's up to the caller to make sure the service actually matches
 | 
						|
	// the pods of the rc.
 | 
						|
	for _, svcPath := range s.svcCfgPaths {
 | 
						|
		svc := svcFromManifest(svcPath)
 | 
						|
		svc.Namespace = namespace
 | 
						|
		svc, err = s.client.Core().Services(svc.Namespace).Create(svc)
 | 
						|
		if err != nil {
 | 
						|
			return
 | 
						|
		}
 | 
						|
		// TODO: This is short term till we have an Ingress.
 | 
						|
		s.svcNames = append(s.svcNames, svc.Name)
 | 
						|
	}
 | 
						|
	s.name = s.svcNames[0]
 | 
						|
	s.namespace = namespace
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (s *ingManager) test(path string) error {
 | 
						|
	url := fmt.Sprintf("%v/hostName", path)
 | 
						|
	httpClient := &http.Client{}
 | 
						|
	return wait.Poll(pollInterval, framework.ServiceRespondingTimeout, func() (bool, error) {
 | 
						|
		body, err := simpleGET(httpClient, url, "")
 | 
						|
		if err != nil {
 | 
						|
			framework.Logf("%v\n%v\n%v", url, body, err)
 | 
						|
			return false, nil
 | 
						|
		}
 | 
						|
		return true, nil
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
var _ = framework.KubeDescribe("ServiceLoadBalancer [Feature:ServiceLoadBalancer]", func() {
 | 
						|
	// These variables are initialized after framework's beforeEach.
 | 
						|
	var ns string
 | 
						|
	var client clientset.Interface
 | 
						|
 | 
						|
	f := framework.NewDefaultFramework("servicelb")
 | 
						|
 | 
						|
	BeforeEach(func() {
 | 
						|
		client = f.ClientSet
 | 
						|
		ns = f.Namespace.Name
 | 
						|
	})
 | 
						|
 | 
						|
	It("should support simple GET on Ingress ips", func() {
 | 
						|
		for _, t := range getLoadBalancerControllers(client) {
 | 
						|
			By(fmt.Sprintf("Starting loadbalancer controller %v in namespace %v", t.getName(), ns))
 | 
						|
			Expect(t.start(ns)).NotTo(HaveOccurred())
 | 
						|
 | 
						|
			for _, s := range getIngManagers(client) {
 | 
						|
				By(fmt.Sprintf("Starting ingress manager %v in namespace %v", s.getName(), ns))
 | 
						|
				Expect(s.start(ns)).NotTo(HaveOccurred())
 | 
						|
 | 
						|
				for _, sName := range s.svcNames {
 | 
						|
					path := t.lookup(sName)
 | 
						|
					framework.Logf("Testing path %v", path)
 | 
						|
					Expect(s.test(path)).NotTo(HaveOccurred())
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			Expect(t.stop()).NotTo(HaveOccurred())
 | 
						|
		}
 | 
						|
	})
 | 
						|
})
 | 
						|
 | 
						|
// simpleGET executes a get on the given url, returns error if non-200 returned.
 | 
						|
func simpleGET(c *http.Client, url, host string) (string, error) {
 | 
						|
	req, err := http.NewRequest("GET", url, nil)
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
	req.Host = host
 | 
						|
	res, err := c.Do(req)
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
	defer res.Body.Close()
 | 
						|
	rawBody, err := ioutil.ReadAll(res.Body)
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
	body := string(rawBody)
 | 
						|
	if res.StatusCode != http.StatusOK {
 | 
						|
		err = fmt.Errorf(
 | 
						|
			"GET returned http error %v", res.StatusCode)
 | 
						|
	}
 | 
						|
	return body, err
 | 
						|
}
 | 
						|
 | 
						|
// rcFromManifest reads a .json/yaml file and returns the rc in it.
 | 
						|
func rcFromManifest(fileName string) *v1.ReplicationController {
 | 
						|
	var controller v1.ReplicationController
 | 
						|
	framework.Logf("Parsing rc from %v", fileName)
 | 
						|
	data := generated.ReadOrDie(fileName)
 | 
						|
 | 
						|
	json, err := utilyaml.ToJSON(data)
 | 
						|
	Expect(err).NotTo(HaveOccurred())
 | 
						|
 | 
						|
	Expect(runtime.DecodeInto(api.Codecs.UniversalDecoder(), json, &controller)).NotTo(HaveOccurred())
 | 
						|
	return &controller
 | 
						|
}
 | 
						|
 | 
						|
// svcFromManifest reads a .json/yaml file and returns the rc in it.
 | 
						|
func svcFromManifest(fileName string) *v1.Service {
 | 
						|
	var svc v1.Service
 | 
						|
	framework.Logf("Parsing service from %v", fileName)
 | 
						|
	data := generated.ReadOrDie(fileName)
 | 
						|
 | 
						|
	json, err := utilyaml.ToJSON(data)
 | 
						|
	Expect(err).NotTo(HaveOccurred())
 | 
						|
 | 
						|
	Expect(runtime.DecodeInto(api.Codecs.UniversalDecoder(), json, &svc)).NotTo(HaveOccurred())
 | 
						|
	return &svc
 | 
						|
}
 |