Merge pull request #20426 from thockin/service-e2e

Service e2e cleanup  and factoring
This commit is contained in:
Saad Ali 2016-02-03 13:10:44 -08:00
commit 351138372e
11 changed files with 824 additions and 570 deletions

View File

@ -162,7 +162,7 @@ var _ = Describe("Upgrade [Feature:Upgrade]", func() {
})
f := NewFramework("cluster-upgrade")
var w *ServerTest
var w *ServiceTestFixture
BeforeEach(func() {
By("Setting up the service, RC, and pods")
w = NewServerTest(f.Client, f.Namespace.Name, svcName)
@ -610,3 +610,57 @@ func migRollingUpdatePoll(id string, nt time.Duration) error {
Logf("MIG rolling update complete after %v", time.Since(start))
return nil
}
func testLoadBalancerReachable(ingress api.LoadBalancerIngress, port int) bool {
return testLoadBalancerReachableInTime(ingress, port, loadBalancerLagTimeout)
}
func testLoadBalancerReachableInTime(ingress api.LoadBalancerIngress, port int, timeout time.Duration) bool {
ip := ingress.IP
if ip == "" {
ip = ingress.Hostname
}
return testReachableInTime(conditionFuncDecorator(ip, port, testReachableHTTP, "/", "test-webserver"), timeout)
}
func conditionFuncDecorator(ip string, port int, fn func(string, int, string, string) (bool, error), request string, expect string) wait.ConditionFunc {
return func() (bool, error) {
return fn(ip, port, request, expect)
}
}
func testReachableInTime(testFunc wait.ConditionFunc, timeout time.Duration) bool {
By(fmt.Sprintf("Waiting up to %v", timeout))
err := wait.PollImmediate(poll, timeout, testFunc)
if err != nil {
Expect(err).NotTo(HaveOccurred(), "Error waiting")
return false
}
return true
}
func waitForLoadBalancerIngress(c *client.Client, serviceName, namespace string) (*api.Service, error) {
// TODO: once support ticket 21807001 is resolved, reduce this timeout
// back to something reasonable
const timeout = 20 * time.Minute
var service *api.Service
By(fmt.Sprintf("waiting up to %v for service %s in namespace %s to have a LoadBalancer ingress point", timeout, serviceName, namespace))
i := 1
for start := time.Now(); time.Since(start) < timeout; time.Sleep(3 * time.Second) {
service, err := c.Services(namespace).Get(serviceName)
if err != nil {
Logf("Get service failed, ignoring for 5s: %v", err)
continue
}
if len(service.Status.LoadBalancer.Ingress) > 0 {
return service, nil
}
if i%5 == 0 {
Logf("Waiting for service %s in namespace %s to have a LoadBalancer ingress point (%v)", serviceName, namespace, time.Since(start))
}
i++
}
return service, fmt.Errorf("service %s in namespace %s doesn't have a LoadBalancer ingress point after %.2f seconds", serviceName, namespace, timeout.Seconds())
}

View File

@ -18,16 +18,17 @@ package e2e
import (
"fmt"
"strings"
. "github.com/onsi/ginkgo"
api "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apimachinery/registered"
client "k8s.io/kubernetes/pkg/client/unversioned"
"strings"
)
const (
kubeletEtcHostsImageName = "gcr.io/google_containers/netexec:1.0"
kubeletEtcHostsImageName = "gcr.io/google_containers/netexec:1.4"
kubeletEtcHostsPodName = "test-pod"
kubeletEtcHostsHostNetworkPodName = "test-host-network-pod"
etcHostsPartialContent = "# Kubernetes-managed hosts file."

View File

@ -46,7 +46,7 @@ const (
nodeHttpPort = 32080
nodeUdpPort = 32081
loadBalancerHttpPort = 100
netexecImageName = "gcr.io/google_containers/netexec:1.0"
netexecImageName = "gcr.io/google_containers/netexec:1.4"
testPodName = "test-container-pod"
hostTestPodName = "host-test-container-pod"
nodePortServiceName = "node-port-service"

View File

@ -19,13 +19,14 @@ package e2e
import (
"encoding/json"
"fmt"
"net/url"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apimachinery/registered"
client "k8s.io/kubernetes/pkg/client/unversioned"
"net/url"
)
const (
@ -36,7 +37,7 @@ const (
notPrivilegedHttpPort = 9090
notPrivilegedUdpPort = 9091
notPrivilegedContainerName = "not-privileged-container"
privilegedContainerImage = "gcr.io/google_containers/netexec:1.1"
privilegedContainerImage = "gcr.io/google_containers/netexec:1.4"
privilegedCommand = "ip link add dummy1 type dummy"
)

View File

@ -112,7 +112,7 @@ func ServeImageOrFail(f *Framework, test string, image string) {
By("Trying to dial each unique pod")
retryTimeout := 2 * time.Minute
retryInterval := 5 * time.Second
err = wait.Poll(retryInterval, retryTimeout, podResponseChecker{f.Client, f.Namespace.Name, label, name, true, pods}.checkAllResponses)
err = wait.Poll(retryInterval, retryTimeout, podProxyResponseChecker{f.Client, f.Namespace.Name, label, name, true, pods}.checkAllResponses)
if err != nil {
Failf("Did not get expected responses within the timeout period of %.2f seconds.", retryTimeout.Seconds())
}

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,7 @@ spec:
spec:
containers:
- name: netexec
image: gcr.io/google_containers/netexec:1.0
image: gcr.io/google_containers/netexec:1.4
ports:
- containerPort: 8080
# This is to force these pods to land on different hosts.

View File

@ -744,13 +744,13 @@ func deleteNS(c *client.Client, namespace string, timeout time.Duration) error {
return nil
}
// Waits default ammount of time (podStartTimeout) for the specified pod to become running.
// Waits default amount of time (podStartTimeout) for the specified pod to become running.
// Returns an error if timeout occurs first, or pod goes in to failed state.
func waitForPodRunningInNamespace(c *client.Client, podName string, namespace string) error {
return waitTimeoutForPodRunningInNamespace(c, podName, namespace, podStartTimeout)
}
// Waits an extended ammount of time (slowPodStartTimeout) for the specified pod to become running.
// Waits an extended amount of time (slowPodStartTimeout) for the specified pod to become running.
// Returns an error if timeout occurs first, or pod goes in to failed state.
func waitForPodRunningInNamespaceSlow(c *client.Client, podName string, namespace string) error {
return waitTimeoutForPodRunningInNamespace(c, podName, namespace, slowPodStartTimeout)
@ -946,8 +946,9 @@ func waitForEndpoint(c *client.Client, ns, name string) error {
return fmt.Errorf("Failed to get entpoints for %s/%s", ns, name)
}
// Context for checking pods responses by issuing GETs to them and verifying if the answer with pod name.
type podResponseChecker struct {
// Context for checking pods responses by issuing GETs to them (via the API
// proxy) and verifying that they answer with ther own pod name.
type podProxyResponseChecker struct {
c *client.Client
ns string
label labels.Selector
@ -956,8 +957,9 @@ type podResponseChecker struct {
pods *api.PodList
}
// checkAllResponses issues GETs to all pods in the context and verify they reply with pod name.
func (r podResponseChecker) checkAllResponses() (done bool, err error) {
// checkAllResponses issues GETs to all pods in the context and verify they
// reply with their own pod name.
func (r podProxyResponseChecker) checkAllResponses() (done bool, err error) {
successes := 0
options := api.ListOptions{LabelSelector: r.label}
currentPods, err := r.c.Pods(r.ns).List(options)
@ -1042,7 +1044,7 @@ func serverVersionGTE(v semver.Version, c client.ServerVersionInterface) (bool,
func podsResponding(c *client.Client, ns, name string, wantName bool, pods *api.PodList) error {
By("trying to dial each unique pod")
label := labels.SelectorFromSet(labels.Set(map[string]string{"name": name}))
return wait.PollImmediate(poll, podRespondingTimeout, podResponseChecker{c, ns, label, name, wantName, pods}.checkAllResponses)
return wait.PollImmediate(poll, podRespondingTimeout, podProxyResponseChecker{c, ns, label, name, wantName, pods}.checkAllResponses)
}
func serviceResponding(c *client.Client, ns, name string) error {
@ -2338,7 +2340,7 @@ func getSigner(provider string) (ssh.Signer, error) {
// in namespace ns are running and ready, using c and waiting at most timeout.
func checkPodsRunningReady(c *client.Client, ns string, podNames []string, timeout time.Duration) bool {
np, desc := len(podNames), "running and ready"
Logf("Waiting up to %v for the following %d pods to be %s: %s", timeout, np, desc, podNames)
Logf("Waiting up to %v for %d pods to be %s: %s", timeout, np, desc, podNames)
result := make(chan bool, len(podNames))
for ix := range podNames {
// Launch off pod readiness checkers.

View File

@ -1,6 +1,6 @@
.PHONY: all netexec image push clean
TAG = 1.3.1
TAG = 1.4
PREFIX = gcr.io/google_containers

View File

@ -56,15 +56,45 @@ func main() {
}
func startHTTPServer(httpPort int) {
http.HandleFunc("/shutdown", shutdownHandler)
http.HandleFunc("/hostName", hostNameHandler)
http.HandleFunc("/", rootHandler)
http.HandleFunc("/echo", echoHandler)
http.HandleFunc("/exit", exitHandler)
http.HandleFunc("/hostname", hostnameHandler)
http.HandleFunc("/shell", shellHandler)
http.HandleFunc("/upload", uploadHandler)
http.HandleFunc("/dial", dialHandler)
// older handlers
http.HandleFunc("/hostName", hostNameHandler)
http.HandleFunc("/shutdown", shutdownHandler)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", httpPort), nil))
}
func rootHandler(w http.ResponseWriter, r *http.Request) {
log.Printf("GET /")
fmt.Fprintf(w, "NOW: %v", time.Now())
}
func echoHandler(w http.ResponseWriter, r *http.Request) {
log.Printf("GET /echo?msg=%s", r.FormValue("msg"))
fmt.Fprintf(w, "%s", r.FormValue("msg"))
}
func exitHandler(w http.ResponseWriter, r *http.Request) {
log.Printf("GET /exit?code=%s", r.FormValue("code"))
code, err := strconv.Atoi(r.FormValue("code"))
if err == nil || r.FormValue("code") == "" {
os.Exit(code)
}
fmt.Fprintf(w, "argument 'code' must be an integer [0-127] or empty, got %q", r.FormValue("code"))
}
func hostnameHandler(w http.ResponseWriter, r *http.Request) {
log.Printf("GET /hostname")
fmt.Fprintf(w, getHostName())
}
func shutdownHandler(w http.ResponseWriter, r *http.Request) {
log.Printf("GET /shutdown")
os.Exit(0)
}
@ -80,6 +110,7 @@ func dialHandler(w http.ResponseWriter, r *http.Request) {
request := values.Query().Get("request") // hostName
protocol := values.Query().Get("protocol")
tryParam := values.Query().Get("tries")
log.Printf("GET /dial?host=%s&protocol=%s&port=%s&request=%s&tries=%s", host, protocol, port, request, tryParam)
tries := 1
if len(tryParam) > 0 {
tries, err = strconv.Atoi(tryParam)
@ -192,9 +223,12 @@ func dialUDP(request string, remoteAddress *net.UDPAddr) (string, error) {
}
func shellHandler(w http.ResponseWriter, r *http.Request) {
log.Println(r.FormValue("shellCommand"))
log.Printf("%s %s %s\n", shellPath, "-c", r.FormValue("shellCommand"))
cmdOut, err := exec.Command(shellPath, "-c", r.FormValue("shellCommand")).CombinedOutput()
cmd := r.FormValue("shellCommand")
if cmd == "" {
cmd = r.FormValue("cmd")
}
log.Printf("GET /shell?cmd=%s", cmd)
cmdOut, err := exec.Command(shellPath, "-c", cmd).CombinedOutput()
output := map[string]string{}
if len(cmdOut) > 0 {
output["output"] = string(cmdOut)
@ -212,6 +246,7 @@ func shellHandler(w http.ResponseWriter, r *http.Request) {
}
func uploadHandler(w http.ResponseWriter, r *http.Request) {
log.Printf("GET /upload")
result := map[string]string{}
file, _, err := r.FormFile("file")
if err != nil {
@ -287,10 +322,19 @@ func startUDPServer(udpPort int) {
n, clientAddress, err := serverConn.ReadFromUDP(buf)
assertNoError(err)
receivedText := strings.TrimSpace(string(buf[0:n]))
if receivedText == "hostName" {
if receivedText == "hostName" || receivedText == "hostname" {
log.Println("Sending udp hostName response")
_, err = serverConn.WriteToUDP([]byte(getHostName()), clientAddress)
assertNoError(err)
} else if strings.HasPrefix(receivedText, "echo ") {
parts := strings.SplitN(receivedText, " ", 2)
resp := ""
if len(parts) == 2 {
resp = parts[1]
}
log.Println("Echoing %q")
_, err = serverConn.WriteToUDP([]byte(resp), clientAddress)
assertNoError(err)
} else if len(receivedText) > 0 {
log.Println("Unknown udp command received. ", receivedText)
}

View File

@ -7,7 +7,9 @@ metadata:
spec:
containers:
- name: netexec
image: gcr.io/google_containers/netexec:1.3.1
image: gcr.io/google_containers/netexec:1.4
ports:
- containerPort: 8080
protocol: TCP
- containerPort: 8081
protocol: UDP