2015-02-20 17:35:42 +00:00
|
|
|
/*
|
2015-05-01 16:19:44 +00:00
|
|
|
Copyright 2015 The Kubernetes Authors All rights reserved.
|
2015-02-20 17:35:42 +00:00
|
|
|
|
|
|
|
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 (
|
|
|
|
"encoding/json"
|
2015-03-26 20:34:18 +00:00
|
|
|
"errors"
|
2015-03-26 19:22:04 +00:00
|
|
|
"fmt"
|
2015-02-20 17:35:42 +00:00
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
2015-04-02 20:15:39 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
2015-03-05 04:35:51 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
|
|
|
|
2015-02-20 17:35:42 +00:00
|
|
|
. "github.com/onsi/ginkgo"
|
2015-04-30 02:53:09 +00:00
|
|
|
. "github.com/onsi/gomega"
|
2015-02-20 17:35:42 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2015-03-31 17:25:20 +00:00
|
|
|
nautilusImage = "gcr.io/google_containers/update-demo:nautilus"
|
|
|
|
kittenImage = "gcr.io/google_containers/update-demo:kitten"
|
2015-03-13 16:26:41 +00:00
|
|
|
updateDemoSelector = "name=update-demo"
|
|
|
|
updateDemoContainer = "update-demo"
|
|
|
|
frontendSelector = "name=frontend"
|
|
|
|
redisMasterSelector = "name=redis-master"
|
|
|
|
redisSlaveSelector = "name=redis-slave"
|
|
|
|
kubectlProxyPort = 8011
|
2015-03-18 14:16:26 +00:00
|
|
|
guestbookStartupTimeout = 10 * time.Minute
|
2015-03-24 12:59:45 +00:00
|
|
|
guestbookResponseTimeout = 3 * time.Minute
|
2015-02-20 17:35:42 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var _ = Describe("kubectl", func() {
|
2015-05-19 16:13:08 +00:00
|
|
|
defer GinkgoRecover()
|
2015-03-05 04:35:51 +00:00
|
|
|
var c *client.Client
|
2015-04-30 02:53:09 +00:00
|
|
|
var ns string
|
|
|
|
var testingNs *api.Namespace
|
2015-03-02 18:15:34 +00:00
|
|
|
BeforeEach(func() {
|
2015-03-05 04:35:51 +00:00
|
|
|
var err error
|
|
|
|
c, err = loadClient()
|
|
|
|
expectNoError(err)
|
2015-04-30 02:53:09 +00:00
|
|
|
testingNs, err = createTestingNS("kubectl", c)
|
|
|
|
ns = testingNs.Name
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
})
|
|
|
|
|
|
|
|
AfterEach(func() {
|
|
|
|
By(fmt.Sprintf("Destroying namespace for this suite %v", ns))
|
|
|
|
if err := c.Namespaces().Delete(ns); err != nil {
|
|
|
|
Failf("Couldn't delete ns %s", err)
|
|
|
|
}
|
2015-03-02 18:15:34 +00:00
|
|
|
})
|
2015-02-20 17:35:42 +00:00
|
|
|
|
2015-03-13 16:26:41 +00:00
|
|
|
Describe("update-demo", func() {
|
2015-05-19 16:13:08 +00:00
|
|
|
var updateDemoRoot, nautilusPath, kittenPath string
|
|
|
|
BeforeEach(func() {
|
2015-04-20 19:51:16 +00:00
|
|
|
updateDemoRoot = filepath.Join(testContext.RepoRoot, "examples/update-demo")
|
2015-05-19 16:13:08 +00:00
|
|
|
nautilusPath = filepath.Join(updateDemoRoot, "nautilus-rc.yaml")
|
|
|
|
kittenPath = filepath.Join(updateDemoRoot, "kitten-rc.yaml")
|
|
|
|
})
|
2015-03-13 16:26:41 +00:00
|
|
|
|
|
|
|
It("should create and stop a replication controller", func() {
|
2015-05-15 09:39:30 +00:00
|
|
|
defer cleanup(nautilusPath, ns, updateDemoSelector)
|
2015-03-13 16:26:41 +00:00
|
|
|
|
|
|
|
By("creating a replication controller")
|
2015-04-30 02:53:09 +00:00
|
|
|
runKubectl("create", "-f", nautilusPath, fmt.Sprintf("--namespace=%v", ns))
|
|
|
|
validateController(c, nautilusImage, 2, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
|
2015-03-13 16:26:41 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
It("should scale a replication controller", func() {
|
2015-05-15 09:39:30 +00:00
|
|
|
defer cleanup(nautilusPath, ns, updateDemoSelector)
|
2015-03-13 16:26:41 +00:00
|
|
|
|
|
|
|
By("creating a replication controller")
|
2015-04-30 02:53:09 +00:00
|
|
|
runKubectl("create", "-f", nautilusPath, fmt.Sprintf("--namespace=%v", ns))
|
|
|
|
validateController(c, nautilusImage, 2, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
|
2015-03-13 16:26:41 +00:00
|
|
|
By("scaling down the replication controller")
|
2015-04-30 02:53:09 +00:00
|
|
|
runKubectl("resize", "rc", "update-demo-nautilus", "--replicas=1", fmt.Sprintf("--namespace=%v", ns))
|
|
|
|
validateController(c, nautilusImage, 1, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
|
2015-03-13 16:26:41 +00:00
|
|
|
By("scaling up the replication controller")
|
2015-04-30 02:53:09 +00:00
|
|
|
runKubectl("resize", "rc", "update-demo-nautilus", "--replicas=2", fmt.Sprintf("--namespace=%v", ns))
|
|
|
|
validateController(c, nautilusImage, 2, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
|
2015-03-13 16:26:41 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
It("should do a rolling update of a replication controller", func() {
|
|
|
|
By("creating the initial replication controller")
|
2015-04-30 02:53:09 +00:00
|
|
|
runKubectl("create", "-f", nautilusPath, fmt.Sprintf("--namespace=%v", ns))
|
|
|
|
validateController(c, nautilusImage, 2, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
|
2015-03-27 23:24:59 +00:00
|
|
|
By("rolling-update to new replication controller")
|
2015-04-30 02:53:09 +00:00
|
|
|
runKubectl("rolling-update", "update-demo-nautilus", "--update-period=1s", "-f", kittenPath, fmt.Sprintf("--namespace=%v", ns))
|
|
|
|
validateController(c, kittenImage, 2, "update-demo", updateDemoSelector, getUDData("kitten.jpg", ns), ns)
|
2015-05-15 03:10:32 +00:00
|
|
|
// Everything will hopefully be cleaned up when the namespace is deleted.
|
2015-03-13 16:26:41 +00:00
|
|
|
})
|
2015-02-20 17:35:42 +00:00
|
|
|
})
|
|
|
|
|
2015-03-13 16:26:41 +00:00
|
|
|
Describe("guestbook", func() {
|
2015-05-19 16:13:08 +00:00
|
|
|
var guestbookPath string
|
|
|
|
BeforeEach(func() {
|
|
|
|
guestbookPath = filepath.Join(testContext.RepoRoot, "examples/guestbook")
|
|
|
|
})
|
2015-03-13 16:26:41 +00:00
|
|
|
|
|
|
|
It("should create and stop a working application", func() {
|
2015-04-18 22:30:10 +00:00
|
|
|
if !providerIs("gce", "gke") {
|
|
|
|
By(fmt.Sprintf("Skipping guestbook, uses createExternalLoadBalancer, a (gce|gke) feature"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-05-15 09:39:30 +00:00
|
|
|
defer cleanup(guestbookPath, ns, frontendSelector, redisMasterSelector, redisSlaveSelector)
|
2015-02-20 17:35:42 +00:00
|
|
|
|
2015-03-13 16:26:41 +00:00
|
|
|
By("creating all guestbook components")
|
2015-04-30 02:53:09 +00:00
|
|
|
runKubectl("create", "-f", guestbookPath, fmt.Sprintf("--namespace=%v", ns))
|
2015-02-20 17:35:42 +00:00
|
|
|
|
2015-03-13 16:26:41 +00:00
|
|
|
By("validating guestbook app")
|
2015-04-30 02:53:09 +00:00
|
|
|
validateGuestbookApp(c, ns)
|
2015-03-13 16:26:41 +00:00
|
|
|
})
|
2015-02-20 17:35:42 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
})
|
|
|
|
|
2015-04-30 02:53:09 +00:00
|
|
|
func validateGuestbookApp(c *client.Client, ns string) {
|
2015-03-18 14:16:26 +00:00
|
|
|
Logf("Waiting for frontend to serve content.")
|
2015-04-30 02:53:09 +00:00
|
|
|
if !waitForGuestbookResponse(c, "get", "", `{"data": ""}`, guestbookStartupTimeout, ns) {
|
2015-03-18 14:16:26 +00:00
|
|
|
Failf("Frontend service did not start serving content in %v seconds.", guestbookStartupTimeout.Seconds())
|
2015-03-13 16:26:41 +00:00
|
|
|
}
|
|
|
|
|
2015-03-18 14:16:26 +00:00
|
|
|
Logf("Trying to add a new entry to the guestbook.")
|
2015-04-30 02:53:09 +00:00
|
|
|
if !waitForGuestbookResponse(c, "set", "TestEntry", `{"message": "Updated"}`, guestbookResponseTimeout, ns) {
|
2015-03-18 14:16:26 +00:00
|
|
|
Failf("Cannot added new entry in %v seconds.", guestbookResponseTimeout.Seconds())
|
2015-03-13 16:26:41 +00:00
|
|
|
}
|
|
|
|
|
2015-03-18 14:16:26 +00:00
|
|
|
Logf("Verifying that added entry can be retrieved.")
|
2015-04-30 02:53:09 +00:00
|
|
|
if !waitForGuestbookResponse(c, "get", "", `{"data": "TestEntry"}`, guestbookResponseTimeout, ns) {
|
2015-03-18 14:16:26 +00:00
|
|
|
Failf("Entry to guestbook wasn't correctly added in %v seconds.", guestbookResponseTimeout.Seconds())
|
2015-03-13 16:26:41 +00:00
|
|
|
}
|
2015-03-18 14:16:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Returns whether received expected response from guestbook on time.
|
2015-04-30 02:53:09 +00:00
|
|
|
func waitForGuestbookResponse(c *client.Client, cmd, arg, expectedResponse string, timeout time.Duration, ns string) bool {
|
2015-05-19 18:17:32 +00:00
|
|
|
for start := time.Now(); time.Since(start) < timeout; time.Sleep(5 * time.Second) {
|
2015-04-30 02:53:09 +00:00
|
|
|
res, err := makeRequestToGuestbook(c, cmd, arg, ns)
|
2015-03-18 14:16:26 +00:00
|
|
|
if err == nil && res == expectedResponse {
|
2015-05-19 18:17:32 +00:00
|
|
|
return true
|
2015-03-18 14:16:26 +00:00
|
|
|
}
|
2015-05-19 18:17:32 +00:00
|
|
|
}
|
|
|
|
return false
|
2015-03-13 16:26:41 +00:00
|
|
|
}
|
|
|
|
|
2015-04-30 02:53:09 +00:00
|
|
|
func makeRequestToGuestbook(c *client.Client, cmd, value string, ns string) (string, error) {
|
2015-03-13 16:26:41 +00:00
|
|
|
result, err := c.Get().
|
|
|
|
Prefix("proxy").
|
2015-04-30 02:53:09 +00:00
|
|
|
Namespace(ns).
|
2015-03-13 16:26:41 +00:00
|
|
|
Resource("services").
|
|
|
|
Name("frontend").
|
|
|
|
Suffix("/index.php").
|
|
|
|
Param("cmd", cmd).
|
|
|
|
Param("key", "messages").
|
|
|
|
Param("value", value).
|
|
|
|
Do().
|
|
|
|
Raw()
|
|
|
|
return string(result), err
|
|
|
|
}
|
|
|
|
|
2015-03-26 20:34:18 +00:00
|
|
|
type updateDemoData struct {
|
|
|
|
Image string
|
2015-03-26 19:22:04 +00:00
|
|
|
}
|
|
|
|
|
2015-03-26 20:34:18 +00:00
|
|
|
// getUDData creates a validator function based on the input string (i.e. kitten.jpg).
|
|
|
|
// For example, if you send "kitten.jpg", this function veridies that the image jpg = kitten.jpg
|
|
|
|
// in the container's json field.
|
2015-04-30 02:53:09 +00:00
|
|
|
func getUDData(jpgExpected string, ns string) func(*client.Client, string) error {
|
2015-03-26 20:34:18 +00:00
|
|
|
|
|
|
|
// getUDData validates data.json in the update-demo (returns nil if data is ok).
|
|
|
|
return func(c *client.Client, podID string) error {
|
|
|
|
Logf("validating pod %s", podID)
|
|
|
|
body, err := c.Get().
|
|
|
|
Prefix("proxy").
|
2015-04-30 02:53:09 +00:00
|
|
|
Namespace(ns).
|
2015-03-26 20:34:18 +00:00
|
|
|
Resource("pods").
|
|
|
|
Name(podID).
|
|
|
|
Suffix("data.json").
|
|
|
|
Do().
|
|
|
|
Raw()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2015-03-26 19:22:04 +00:00
|
|
|
}
|
2015-03-26 20:34:18 +00:00
|
|
|
Logf("got data: %s", body)
|
|
|
|
var data updateDemoData
|
|
|
|
if err := json.Unmarshal(body, &data); err != nil {
|
|
|
|
return err
|
2015-03-26 19:22:04 +00:00
|
|
|
}
|
2015-03-26 20:34:18 +00:00
|
|
|
Logf("Unmarshalled json jpg/img => %s , expecting %s .", data, jpgExpected)
|
|
|
|
if strings.Contains(data.Image, jpgExpected) {
|
|
|
|
return nil
|
|
|
|
} else {
|
|
|
|
return errors.New(fmt.Sprintf("data served up in container is innaccurate, %s didn't contain %s", data, jpgExpected))
|
2015-03-26 19:22:04 +00:00
|
|
|
}
|
|
|
|
}
|
2015-02-20 17:35:42 +00:00
|
|
|
}
|