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 (
2015-09-10 21:32:57 +00:00
"bytes"
2015-02-20 17:35:42 +00:00
"encoding/json"
2015-03-26 20:34:18 +00:00
"errors"
2015-03-26 19:22:04 +00:00
"fmt"
2015-08-31 17:23:47 +00:00
"io"
2015-06-30 16:43:37 +00:00
"io/ioutil"
2015-09-17 20:11:27 +00:00
"mime/multipart"
2015-07-07 10:39:38 +00:00
"net"
2015-06-30 16:43:37 +00:00
"net/http"
2015-10-19 18:17:02 +00:00
"net/url"
2015-07-07 10:39:38 +00:00
"os"
2015-07-07 05:09:22 +00:00
"os/exec"
2015-09-29 15:20:49 +00:00
"path"
2015-02-20 17:35:42 +00:00
"path/filepath"
2015-06-30 16:43:37 +00:00
"regexp"
2015-07-07 05:09:22 +00:00
"strconv"
2015-02-20 17:35:42 +00:00
"strings"
"time"
2015-09-10 21:32:57 +00:00
"github.com/ghodss/yaml"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/api"
2015-09-10 01:28:53 +00:00
apierrs "k8s.io/kubernetes/pkg/api/errors"
2015-10-09 01:32:15 +00:00
"k8s.io/kubernetes/pkg/api/unversioned"
2015-08-13 19:01:50 +00:00
client "k8s.io/kubernetes/pkg/client/unversioned"
2015-09-10 21:32:57 +00:00
"k8s.io/kubernetes/pkg/kubectl"
2015-11-13 01:07:21 +00:00
"k8s.io/kubernetes/pkg/kubectl/cmd/util"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/labels"
2015-09-10 01:28:53 +00:00
"k8s.io/kubernetes/pkg/util/wait"
2016-01-13 19:27:40 +00:00
"k8s.io/kubernetes/pkg/version"
2015-03-05 04:35:51 +00:00
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"
2015-09-23 09:37:47 +00:00
frontendSelector = "app=guestbook,tier=frontend"
redisMasterSelector = "app=redis,role=master"
redisSlaveSelector = "app=redis,role=slave"
2015-09-17 20:11:27 +00:00
goproxyContainer = "goproxy"
goproxyPodSelector = "name=goproxy"
netexecContainer = "netexec"
netexecPodSelector = "name=netexec"
2015-03-13 16:26:41 +00:00
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-06-30 16:43:37 +00:00
simplePodSelector = "name=nginx"
simplePodName = "nginx"
nginxDefaultOutput = "Welcome to nginx!"
simplePodPort = 80
2016-01-08 16:14:55 +00:00
runJobTimeout = 5 * time . Minute
2015-06-30 16:43:37 +00:00
)
2016-01-13 19:27:40 +00:00
var (
proxyRegexp = regexp . MustCompile ( "Starting to serve on 127.0.0.1:([0-9]+)" )
// Extended pod logging options were introduced in #13780 (v1.1.0) so we don't expect tests
// that rely on extended pod logging options to work on clusters before that.
//
// TODO(ihmccreery): remove once we don't care about v1.0 anymore, (tentatively in v1.3).
extendedPodLogFilterVersion = version . MustParse ( "v1.1.0" )
// NodePorts were made optional in #12831 (v1.1.0) so we don't expect tests that used to
// require NodePorts but no longer include them to work on clusters before that.
//
// TODO(ihmccreery): remove once we don't care about v1.0 anymore, (tentatively in v1.3).
nodePortsOptionalVersion = version . MustParse ( "v1.1.0" )
// Jobs were introduced in v1.1, so we don't expect tests that rely on jobs to work on
// clusters before that.
//
// TODO(ihmccreery): remove once we don't care about v1.0 anymore, (tentatively in v1.3).
jobsVersion = version . MustParse ( "v1.1.0" )
)
2015-02-20 17:35:42 +00:00
2015-06-03 03:23:44 +00:00
var _ = Describe ( "Kubectl client" , func ( ) {
2015-05-19 16:13:08 +00:00
defer GinkgoRecover ( )
2015-10-27 08:24:32 +00:00
framework := NewFramework ( "kubectl" )
2015-03-05 04:35:51 +00:00
var c * client . Client
2015-04-30 02:53:09 +00:00
var ns string
2015-03-02 18:15:34 +00:00
BeforeEach ( func ( ) {
2015-10-27 08:24:32 +00:00
c = framework . Client
ns = framework . Namespace . Name
2015-03-02 18:15:34 +00:00
} )
2015-02-20 17:35:42 +00:00
2015-06-03 03:23:44 +00:00
Describe ( "Update Demo" , func ( ) {
2015-05-19 16:13:08 +00:00
var updateDemoRoot , nautilusPath , kittenPath string
BeforeEach ( func ( ) {
2015-07-14 22:57:41 +00:00
updateDemoRoot = filepath . Join ( testContext . RepoRoot , "docs/user-guide/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-10-07 14:09:24 +00:00
It ( "should create and stop a replication controller [Conformance]" , 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-11-08 18:58:21 +00:00
runKubectlOrDie ( "create" , "-f" , nautilusPath , fmt . Sprintf ( "--namespace=%v" , ns ) )
2015-04-30 02:53:09 +00:00
validateController ( c , nautilusImage , 2 , "update-demo" , updateDemoSelector , getUDData ( "nautilus.jpg" , ns ) , ns )
2015-03-13 16:26:41 +00:00
} )
2015-10-07 14:09:24 +00:00
It ( "should scale a replication controller [Conformance]" , 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-11-08 18:58:21 +00:00
runKubectlOrDie ( "create" , "-f" , nautilusPath , fmt . Sprintf ( "--namespace=%v" , ns ) )
2015-04-30 02:53:09 +00:00
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-11-08 18:58:21 +00:00
runKubectlOrDie ( "scale" , "rc" , "update-demo-nautilus" , "--replicas=1" , "--timeout=5m" , fmt . Sprintf ( "--namespace=%v" , ns ) )
2015-04-30 02:53:09 +00:00
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-11-08 18:58:21 +00:00
runKubectlOrDie ( "scale" , "rc" , "update-demo-nautilus" , "--replicas=2" , "--timeout=5m" , fmt . Sprintf ( "--namespace=%v" , ns ) )
2015-04-30 02:53:09 +00:00
validateController ( c , nautilusImage , 2 , "update-demo" , updateDemoSelector , getUDData ( "nautilus.jpg" , ns ) , ns )
2015-03-13 16:26:41 +00:00
} )
2015-10-07 14:09:24 +00:00
It ( "should do a rolling update of a replication controller [Conformance]" , func ( ) {
2015-03-13 16:26:41 +00:00
By ( "creating the initial replication controller" )
2015-11-08 18:58:21 +00:00
runKubectlOrDie ( "create" , "-f" , nautilusPath , fmt . Sprintf ( "--namespace=%v" , ns ) )
2015-04-30 02:53:09 +00:00
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-11-08 18:58:21 +00:00
runKubectlOrDie ( "rolling-update" , "update-demo-nautilus" , "--update-period=1s" , "-f" , kittenPath , fmt . Sprintf ( "--namespace=%v" , ns ) )
2015-06-23 03:58:48 +00:00
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-06-03 03:23:44 +00:00
Describe ( "Guestbook application" , func ( ) {
2015-05-19 16:13:08 +00:00
var guestbookPath string
2015-06-22 21:14:54 +00:00
2015-05-19 16:13:08 +00:00
BeforeEach ( func ( ) {
guestbookPath = filepath . Join ( testContext . RepoRoot , "examples/guestbook" )
} )
2015-03-13 16:26:41 +00:00
2015-10-07 14:09:24 +00:00
It ( "should create and stop a working application [Conformance]" , func ( ) {
2016-01-13 19:27:40 +00:00
SkipUnlessServerVersionGTE ( nodePortsOptionalVersion , c )
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-11-08 18:58:21 +00:00
runKubectlOrDie ( "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-06-30 16:43:37 +00:00
Describe ( "Simple pod" , func ( ) {
var podPath string
BeforeEach ( func ( ) {
2016-02-09 23:48:34 +00:00
podPath = filepath . Join ( testContext . RepoRoot , "test" , "e2e" , "testing-manifests" , "kubectl" , "pod-with-readiness-probe.yaml" )
2016-02-08 23:38:17 +00:00
By ( fmt . Sprintf ( "creating the pod from %v" , podPath ) )
2015-11-08 18:58:21 +00:00
runKubectlOrDie ( "create" , "-f" , podPath , fmt . Sprintf ( "--namespace=%v" , ns ) )
2015-06-30 16:43:37 +00:00
checkPodsRunningReady ( c , ns , [ ] string { simplePodName } , podStartTimeout )
} )
AfterEach ( func ( ) {
cleanup ( podPath , ns , simplePodSelector )
} )
It ( "should support exec" , func ( ) {
By ( "executing a command in the container" )
2015-11-08 18:58:21 +00:00
execOutput := runKubectlOrDie ( "exec" , fmt . Sprintf ( "--namespace=%v" , ns ) , simplePodName , "echo" , "running" , "in" , "container" )
2015-08-31 17:23:47 +00:00
if e , a := "running in container" , execOutput ; e != a {
Failf ( "Unexpected kubectl exec output. Wanted %q, got %q" , e , a )
}
By ( "executing a command in the container with noninteractive stdin" )
execOutput = newKubectlCommand ( "exec" , fmt . Sprintf ( "--namespace=%v" , ns ) , "-i" , simplePodName , "cat" ) .
withStdinData ( "abcd1234" ) .
2015-11-08 18:58:21 +00:00
execOrDie ( )
2015-08-31 17:23:47 +00:00
if e , a := "abcd1234" , execOutput ; e != a {
Failf ( "Unexpected kubectl exec output. Wanted %q, got %q" , e , a )
}
// pretend that we're a user in an interactive shell
2015-09-17 20:11:27 +00:00
r , closer , err := newBlockingReader ( "echo hi\nexit\n" )
2015-08-31 17:23:47 +00:00
if err != nil {
Failf ( "Error creating blocking reader: %v" , err )
}
// NOTE this is solely for test cleanup!
2015-09-17 20:11:27 +00:00
defer closer . Close ( )
2015-08-31 17:23:47 +00:00
By ( "executing a command in the container with pseudo-interactive stdin" )
execOutput = newKubectlCommand ( "exec" , fmt . Sprintf ( "--namespace=%v" , ns ) , "-i" , simplePodName , "bash" ) .
withStdinReader ( r ) .
2015-11-08 18:58:21 +00:00
execOrDie ( )
2015-08-31 17:23:47 +00:00
if e , a := "hi" , execOutput ; e != a {
Failf ( "Unexpected kubectl exec output. Wanted %q, got %q" , e , a )
2015-06-30 16:43:37 +00:00
}
} )
2015-08-31 17:23:47 +00:00
2015-10-19 18:17:02 +00:00
It ( "should support exec through an HTTP proxy" , func ( ) {
2015-09-17 20:11:27 +00:00
// Note: We are skipping local since we want to verify an apiserver with HTTPS.
// At this time local only supports plain HTTP.
SkipIfProviderIs ( "local" )
// Fail if the variable isn't set
if testContext . Host == "" {
Failf ( "--host variable must be set to the full URI to the api server on e2e run." )
}
2015-10-19 18:17:02 +00:00
// Make sure the apiServer is set to what kubectl requires
2015-09-17 20:11:27 +00:00
apiServer := testContext . Host
2015-10-19 18:17:02 +00:00
apiServerUrl , err := url . Parse ( apiServer )
if err != nil {
Failf ( "Unable to parse URL %s. Error=%s" , apiServer , err )
2015-09-17 20:11:27 +00:00
}
2015-10-19 18:17:02 +00:00
apiServerUrl . Scheme = "https"
if ! strings . Contains ( apiServer , ":443" ) {
apiServerUrl . Host = apiServerUrl . Host + ":443"
2015-09-17 20:11:27 +00:00
}
2015-10-19 18:17:02 +00:00
apiServer = apiServerUrl . String ( )
2015-09-17 20:11:27 +00:00
2015-09-29 15:20:49 +00:00
// Build the static kubectl
2015-10-19 18:17:02 +00:00
By ( "Finding a static kubectl for upload" )
2015-11-02 17:58:50 +00:00
testStaticKubectlPath , err := findBinary ( "kubectl" , "linux/386" )
2015-09-29 15:20:49 +00:00
if err != nil {
2015-11-02 17:58:50 +00:00
Logf ( "No kubectl found: %v.\nAttempting a local build..." , err )
2015-10-19 18:17:02 +00:00
// Fall back to trying to build a local static kubectl
kubectlContainerPath := path . Join ( testContext . RepoRoot , "/examples/kubectl-container/" )
if _ , err := os . Stat ( path . Join ( testContext . RepoRoot , "hack/build-go.sh" ) ) ; err != nil {
Failf ( "Can't build static kubectl due to missing hack/build-go.sh. Error=%s" , err )
}
By ( "Building a static kubectl for upload" )
staticKubectlBuild := exec . Command ( "make" , "-C" , kubectlContainerPath )
if out , err := staticKubectlBuild . Output ( ) ; err != nil {
Failf ( "Unable to create static kubectl. Error=%s, Output=%q" , err , out )
}
// Verify the static kubectl path
testStaticKubectlPath = path . Join ( kubectlContainerPath , "kubectl" )
_ , err := os . Stat ( testStaticKubectlPath )
if err != nil {
Failf ( "static kubectl path could not be found in %s. Error=%s" , testStaticKubectlPath , err )
}
2015-09-17 20:11:27 +00:00
}
2015-10-19 18:17:02 +00:00
By ( fmt . Sprintf ( "Using the kubectl in %s" , testStaticKubectlPath ) )
2015-09-17 20:11:27 +00:00
2015-09-29 15:20:49 +00:00
// Verify the kubeconfig path
kubeConfigFilePath := testContext . KubeConfig
_ , err = os . Stat ( kubeConfigFilePath )
2015-09-17 20:11:27 +00:00
if err != nil {
Failf ( "kube config path could not be accessed. Error=%s" , err )
}
// start exec-proxy-tester container
netexecPodPath := filepath . Join ( testContext . RepoRoot , "test/images/netexec/pod.yaml" )
2015-11-08 18:58:21 +00:00
runKubectlOrDie ( "create" , "-f" , netexecPodPath , fmt . Sprintf ( "--namespace=%v" , ns ) )
2015-09-17 20:11:27 +00:00
checkPodsRunningReady ( c , ns , [ ] string { netexecContainer } , podStartTimeout )
// Clean up
defer cleanup ( netexecPodPath , ns , netexecPodSelector )
// Upload kubeconfig
type NetexecOutput struct {
Output string ` json:"output" `
Error string ` json:"error" `
}
var uploadConfigOutput NetexecOutput
// Upload the kubeconfig file
By ( "uploading kubeconfig to netexec" )
pipeConfigReader , postConfigBodyWriter , err := newStreamingUpload ( kubeConfigFilePath )
if err != nil {
Failf ( "unable to create streaming upload. Error: %s" , err )
}
2015-12-16 19:18:47 +00:00
subResourceProxyAvailable , err := serverVersionGTE ( subResourceProxyVersion , c )
if err != nil {
Failf ( "Unable to determine server version. Error: %s" , err )
}
var resp [ ] byte
if subResourceProxyAvailable {
resp , err = c . Post ( ) .
Namespace ( ns ) .
Name ( "netexec" ) .
Resource ( "pods" ) .
SubResource ( "proxy" ) .
Suffix ( "upload" ) .
SetHeader ( "Content-Type" , postConfigBodyWriter . FormDataContentType ( ) ) .
Body ( pipeConfigReader ) .
Do ( ) . Raw ( )
} else {
resp , err = c . Post ( ) .
Prefix ( "proxy" ) .
Namespace ( ns ) .
Name ( "netexec" ) .
Resource ( "pods" ) .
Suffix ( "upload" ) .
SetHeader ( "Content-Type" , postConfigBodyWriter . FormDataContentType ( ) ) .
Body ( pipeConfigReader ) .
Do ( ) . Raw ( )
}
2015-09-17 20:11:27 +00:00
if err != nil {
Failf ( "Unable to upload kubeconfig to the remote exec server due to error: %s" , err )
}
if err := json . Unmarshal ( resp , & uploadConfigOutput ) ; err != nil {
Failf ( "Unable to read the result from the netexec server. Error: %s" , err )
}
kubecConfigRemotePath := uploadConfigOutput . Output
// Upload
2015-09-29 15:20:49 +00:00
pipeReader , postBodyWriter , err := newStreamingUpload ( testStaticKubectlPath )
2015-09-17 20:11:27 +00:00
if err != nil {
Failf ( "unable to create streaming upload. Error: %s" , err )
}
By ( "uploading kubectl to netexec" )
var uploadOutput NetexecOutput
// Upload the kubectl binary
2015-12-16 19:18:47 +00:00
if subResourceProxyAvailable {
resp , err = c . Post ( ) .
Namespace ( ns ) .
Name ( "netexec" ) .
Resource ( "pods" ) .
SubResource ( "proxy" ) .
Suffix ( "upload" ) .
SetHeader ( "Content-Type" , postBodyWriter . FormDataContentType ( ) ) .
Body ( pipeReader ) .
Do ( ) . Raw ( )
} else {
resp , err = c . Post ( ) .
Prefix ( "proxy" ) .
Namespace ( ns ) .
Name ( "netexec" ) .
Resource ( "pods" ) .
Suffix ( "upload" ) .
SetHeader ( "Content-Type" , postBodyWriter . FormDataContentType ( ) ) .
Body ( pipeReader ) .
Do ( ) . Raw ( )
}
2015-09-17 20:11:27 +00:00
if err != nil {
Failf ( "Unable to upload kubectl binary to the remote exec server due to error: %s" , err )
}
if err := json . Unmarshal ( resp , & uploadOutput ) ; err != nil {
Failf ( "Unable to read the result from the netexec server. Error: %s" , err )
}
uploadBinaryName := uploadOutput . Output
// Verify that we got the expected response back in the body
if ! strings . HasPrefix ( uploadBinaryName , "/uploads/" ) {
Failf ( "Unable to upload kubectl binary to remote exec server. /uploads/ not in response. Response: %s" , uploadBinaryName )
}
for _ , proxyVar := range [ ] string { "https_proxy" , "HTTPS_PROXY" } {
By ( "Running kubectl in netexec via an HTTP proxy using " + proxyVar )
// start the proxy container
goproxyPodPath := filepath . Join ( testContext . RepoRoot , "test/images/goproxy/pod.yaml" )
2015-11-08 18:58:21 +00:00
runKubectlOrDie ( "create" , "-f" , goproxyPodPath , fmt . Sprintf ( "--namespace=%v" , ns ) )
2015-09-17 20:11:27 +00:00
checkPodsRunningReady ( c , ns , [ ] string { goproxyContainer } , podStartTimeout )
// get the proxy address
goproxyPod , err := c . Pods ( ns ) . Get ( goproxyContainer )
if err != nil {
Failf ( "Unable to get the goproxy pod. Error: %s" , err )
}
proxyAddr := fmt . Sprintf ( "http://%s:8080" , goproxyPod . Status . PodIP )
2016-01-21 23:58:37 +00:00
shellCommand := fmt . Sprintf ( "%s=%s .%s --kubeconfig=%s --server=%s --namespace=%s exec nginx echo running in container" ,
proxyVar , proxyAddr , uploadBinaryName , kubecConfigRemotePath , apiServer , ns )
Logf ( "About to remote exec: %v" , shellCommand )
2015-09-17 20:11:27 +00:00
// Execute kubectl on remote exec server.
2015-12-16 19:18:47 +00:00
var netexecShellOutput [ ] byte
if subResourceProxyAvailable {
netexecShellOutput , err = c . Post ( ) .
Namespace ( ns ) .
Name ( "netexec" ) .
Resource ( "pods" ) .
SubResource ( "proxy" ) .
Suffix ( "shell" ) .
Param ( "shellCommand" , shellCommand ) .
Do ( ) . Raw ( )
} else {
netexecShellOutput , err = c . Post ( ) .
Prefix ( "proxy" ) .
Namespace ( ns ) .
Name ( "netexec" ) .
Resource ( "pods" ) .
Suffix ( "shell" ) .
Param ( "shellCommand" , shellCommand ) .
Do ( ) . Raw ( )
}
2015-09-17 20:11:27 +00:00
if err != nil {
Failf ( "Unable to execute kubectl binary on the remote exec server due to error: %s" , err )
}
var netexecOuput NetexecOutput
if err := json . Unmarshal ( netexecShellOutput , & netexecOuput ) ; err != nil {
Failf ( "Unable to read the result from the netexec server. Error: %s" , err )
}
2016-01-21 23:58:37 +00:00
// Get (and print!) the proxy logs here, so
// they'll be present in case the below check
// fails the test, to help diagnose #19500 if
// it recurs.
proxyLog := runKubectlOrDie ( "log" , "goproxy" , fmt . Sprintf ( "--namespace=%v" , ns ) )
2015-09-17 20:11:27 +00:00
// Verify we got the normal output captured by the exec server
expectedExecOutput := "running in container\n"
if netexecOuput . Output != expectedExecOutput {
Failf ( "Unexpected kubectl exec output. Wanted %q, got %q" , expectedExecOutput , netexecOuput . Output )
}
// Verify the proxy server logs saw the connection
expectedProxyLog := fmt . Sprintf ( "Accepting CONNECT to %s" , strings . TrimRight ( strings . TrimLeft ( testContext . Host , "https://" ) , "/api" ) )
if ! strings . Contains ( proxyLog , expectedProxyLog ) {
Failf ( "Missing expected log result on proxy server for %s. Expected: %q, got %q" , proxyVar , expectedProxyLog , proxyLog )
}
// Clean up the goproxyPod
cleanup ( goproxyPodPath , ns , goproxyPodSelector )
}
} )
2015-09-01 23:42:16 +00:00
It ( "should support inline execution and attach" , func ( ) {
2016-01-13 19:27:40 +00:00
SkipUnlessServerVersionGTE ( jobsVersion , c )
2015-10-06 15:31:48 +00:00
nsFlag := fmt . Sprintf ( "--namespace=%v" , ns )
By ( "executing a command with run and attach with stdin" )
runOutput := newKubectlCommand ( nsFlag , "run" , "run-test" , "--image=busybox" , "--restart=Never" , "--attach=true" , "--stdin" , "--" , "sh" , "-c" , "cat && echo 'stdin closed'" ) .
withStdinData ( "abcd1234" ) .
2015-11-08 18:58:21 +00:00
execOrDie ( )
2015-10-06 15:31:48 +00:00
Expect ( runOutput ) . To ( ContainSubstring ( "abcd1234" ) )
Expect ( runOutput ) . To ( ContainSubstring ( "stdin closed" ) )
2015-11-13 01:07:21 +00:00
Expect ( c . Extensions ( ) . Jobs ( ns ) . Delete ( "run-test" , api . NewDeleteOptions ( 0 ) ) ) . To ( BeNil ( ) )
2015-10-06 15:31:48 +00:00
By ( "executing a command with run and attach without stdin" )
runOutput = newKubectlCommand ( fmt . Sprintf ( "--namespace=%v" , ns ) , "run" , "run-test-2" , "--image=busybox" , "--restart=Never" , "--attach=true" , "--leave-stdin-open=true" , "--" , "sh" , "-c" , "cat && echo 'stdin closed'" ) .
withStdinData ( "abcd1234" ) .
2015-11-08 18:58:21 +00:00
execOrDie ( )
2015-10-06 15:31:48 +00:00
Expect ( runOutput ) . ToNot ( ContainSubstring ( "abcd1234" ) )
Expect ( runOutput ) . To ( ContainSubstring ( "stdin closed" ) )
2015-11-13 01:07:21 +00:00
Expect ( c . Extensions ( ) . Jobs ( ns ) . Delete ( "run-test-2" , api . NewDeleteOptions ( 0 ) ) ) . To ( BeNil ( ) )
2015-10-06 15:31:48 +00:00
By ( "executing a command with run and attach with stdin with open stdin should remain running" )
runOutput = newKubectlCommand ( nsFlag , "run" , "run-test-3" , "--image=busybox" , "--restart=Never" , "--attach=true" , "--leave-stdin-open=true" , "--stdin" , "--" , "sh" , "-c" , "cat && echo 'stdin closed'" ) .
withStdinData ( "abcd1234\n" ) .
2015-11-08 18:58:21 +00:00
execOrDie ( )
2015-10-06 15:31:48 +00:00
Expect ( runOutput ) . ToNot ( ContainSubstring ( "stdin closed" ) )
2016-01-20 00:40:18 +00:00
runTestPod , err := util . GetFirstPod ( c , ns , labels . SelectorFromSet ( map [ string ] string { "run" : "run-test-3" } ) )
2015-11-13 01:07:21 +00:00
if err != nil {
os . Exit ( 1 )
}
if ! checkPodsRunningReady ( c , ns , [ ] string { runTestPod . Name } , time . Minute ) {
Failf ( "Pod %q of Job %q should still be running" , runTestPod . Name , "run-test-3" )
2015-10-06 15:31:48 +00:00
}
// NOTE: we cannot guarantee our output showed up in the container logs before stdin was closed, so we have
// to loop test.
2015-11-13 01:07:21 +00:00
err = wait . PollImmediate ( time . Second , time . Minute , func ( ) ( bool , error ) {
if ! checkPodsRunningReady ( c , ns , [ ] string { runTestPod . Name } , 1 * time . Second ) {
Failf ( "Pod %q of Job %q should still be running" , runTestPod . Name , "run-test-3" )
2015-10-06 15:31:48 +00:00
}
2015-11-13 01:07:21 +00:00
logOutput := runKubectlOrDie ( nsFlag , "logs" , runTestPod . Name )
2015-10-06 15:31:48 +00:00
Expect ( logOutput ) . ToNot ( ContainSubstring ( "stdin closed" ) )
return strings . Contains ( logOutput , "abcd1234" ) , nil
} )
if err != nil {
os . Exit ( 1 )
}
Expect ( err ) . To ( BeNil ( ) )
2015-11-13 01:07:21 +00:00
Expect ( c . Extensions ( ) . Jobs ( ns ) . Delete ( "run-test-3" , api . NewDeleteOptions ( 0 ) ) ) . To ( BeNil ( ) )
2015-09-01 23:42:16 +00:00
} )
2015-06-30 16:43:37 +00:00
It ( "should support port-forward" , func ( ) {
By ( "forwarding the container port to a local port" )
2015-09-22 20:29:51 +00:00
cmd , listenPort := runPortForward ( ns , simplePodName , simplePodPort )
2015-07-07 05:09:22 +00:00
defer tryKill ( cmd )
2015-09-22 20:29:51 +00:00
2015-06-30 16:43:37 +00:00
By ( "curling local port output" )
2015-09-22 20:29:51 +00:00
localAddr := fmt . Sprintf ( "http://localhost:%d" , listenPort )
2015-06-30 16:43:37 +00:00
body , err := curl ( localAddr )
2015-07-07 05:09:22 +00:00
Logf ( "got: %s" , body )
2015-06-30 16:43:37 +00:00
if err != nil {
Failf ( "Failed http.Get of forwarded port (%s): %v" , localAddr , err )
}
if ! strings . Contains ( body , nginxDefaultOutput ) {
Failf ( "Container port output missing expected value. Wanted:'%s', got: %s" , nginxDefaultOutput , body )
}
} )
} )
2015-07-24 08:20:35 +00:00
Describe ( "Kubectl api-versions" , func ( ) {
2015-10-07 14:09:24 +00:00
It ( "should check if v1 is in available api versions [Conformance]" , func ( ) {
2015-07-24 08:20:35 +00:00
By ( "validating api verions" )
2015-11-08 18:58:21 +00:00
output := runKubectlOrDie ( "api-versions" )
2015-07-24 08:20:35 +00:00
if ! strings . Contains ( output , "v1" ) {
Failf ( "No v1 in kubectl api-versions" )
}
2015-07-09 00:14:28 +00:00
} )
2015-07-24 08:20:35 +00:00
} )
2015-07-09 00:14:28 +00:00
2015-09-10 21:32:57 +00:00
Describe ( "Kubectl apply" , func ( ) {
It ( "should apply a new configuration to an existing RC" , func ( ) {
mkpath := func ( file string ) string {
return filepath . Join ( testContext . RepoRoot , "examples/guestbook-go" , file )
}
controllerJson := mkpath ( "redis-master-controller.json" )
nsFlag := fmt . Sprintf ( "--namespace=%v" , ns )
By ( "creating Redis RC" )
2015-11-08 18:58:21 +00:00
runKubectlOrDie ( "create" , "-f" , controllerJson , nsFlag )
2015-09-10 21:32:57 +00:00
By ( "applying a modified configuration" )
stdin := modifyReplicationControllerConfiguration ( controllerJson )
newKubectlCommand ( "apply" , "-f" , "-" , nsFlag ) .
withStdinReader ( stdin ) .
2015-11-08 18:58:21 +00:00
execOrDie ( )
2015-09-10 21:32:57 +00:00
By ( "checking the result" )
forEachReplicationController ( c , ns , "app" , "redis" , validateReplicationControllerConfiguration )
} )
} )
2015-07-24 08:20:35 +00:00
Describe ( "Kubectl cluster-info" , func ( ) {
2015-10-07 14:09:24 +00:00
It ( "should check if Kubernetes master services is included in cluster-info [Conformance]" , func ( ) {
2015-07-24 08:20:35 +00:00
By ( "validating cluster-info" )
2015-11-08 18:58:21 +00:00
output := runKubectlOrDie ( "cluster-info" )
2015-08-08 21:29:57 +00:00
// Can't check exact strings due to terminal control commands (colors)
2015-07-24 08:20:35 +00:00
requiredItems := [ ] string { "Kubernetes master" , "is running at" }
if providerIs ( "gce" , "gke" ) {
requiredItems = append ( requiredItems , "KubeDNS" , "Heapster" )
}
for _ , item := range requiredItems {
if ! strings . Contains ( output , item ) {
Failf ( "Missing %s in kubectl cluster-info" , item )
}
2015-07-09 00:14:28 +00:00
}
2015-07-24 08:20:35 +00:00
} )
} )
2015-07-09 00:14:28 +00:00
2015-07-24 08:20:35 +00:00
Describe ( "Kubectl describe" , func ( ) {
2015-10-07 14:09:24 +00:00
It ( "should check if kubectl describe prints relevant information for rc and pods [Conformance]" , func ( ) {
2016-01-13 19:27:40 +00:00
SkipUnlessServerVersionGTE ( nodePortsOptionalVersion , c )
2015-07-24 08:20:35 +00:00
mkpath := func ( file string ) string {
return filepath . Join ( testContext . RepoRoot , "examples/guestbook-go" , file )
2015-07-09 00:14:28 +00:00
}
2015-07-24 08:20:35 +00:00
controllerJson := mkpath ( "redis-master-controller.json" )
serviceJson := mkpath ( "redis-master-service.json" )
nsFlag := fmt . Sprintf ( "--namespace=%v" , ns )
2015-11-08 18:58:21 +00:00
runKubectlOrDie ( "create" , "-f" , controllerJson , nsFlag )
runKubectlOrDie ( "create" , "-f" , serviceJson , nsFlag )
2015-07-24 08:20:35 +00:00
// Pod
forEachPod ( c , ns , "app" , "redis" , func ( pod api . Pod ) {
2015-11-08 18:58:21 +00:00
output := runKubectlOrDie ( "describe" , "pod" , pod . Name , nsFlag )
2015-07-24 08:20:35 +00:00
requiredStrings := [ ] [ ] string {
{ "Name:" , "redis-master-" } ,
{ "Namespace:" , ns } ,
{ "Image(s):" , "redis" } ,
{ "Node:" } ,
{ "Labels:" , "app=redis" , "role=master" } ,
{ "Status:" , "Running" } ,
{ "Reason:" } ,
{ "Message:" } ,
{ "IP:" } ,
2015-10-28 11:23:33 +00:00
{ "Controllers:" , "ReplicationController/redis-master" } }
2015-07-24 08:20:35 +00:00
checkOutput ( output , requiredStrings )
} )
// Rc
2015-11-08 18:58:21 +00:00
output := runKubectlOrDie ( "describe" , "rc" , "redis-master" , nsFlag )
2015-07-24 08:20:35 +00:00
requiredStrings := [ ] [ ] string {
{ "Name:" , "redis-master" } ,
{ "Namespace:" , ns } ,
{ "Image(s):" , "redis" } ,
{ "Selector:" , "app=redis,role=master" } ,
{ "Labels:" , "app=redis,role=master" } ,
{ "Replicas:" , "1 current" , "1 desired" } ,
{ "Pods Status:" , "1 Running" , "0 Waiting" , "0 Succeeded" , "0 Failed" } ,
2016-01-22 18:56:14 +00:00
// {"Events:"} would ordinarily go in the list
// here, but in some rare circumstances the
// events are delayed, and instead kubectl
// prints "No events." This string will match
// either way.
{ "vents" } }
2015-07-24 08:20:35 +00:00
checkOutput ( output , requiredStrings )
// Service
2015-11-08 18:58:21 +00:00
output = runKubectlOrDie ( "describe" , "service" , "redis-master" , nsFlag )
2015-07-24 08:20:35 +00:00
requiredStrings = [ ] [ ] string {
{ "Name:" , "redis-master" } ,
{ "Namespace:" , ns } ,
{ "Labels:" , "app=redis" , "role=master" } ,
{ "Selector:" , "app=redis" , "role=master" } ,
{ "Type:" , "ClusterIP" } ,
{ "IP:" } ,
{ "Port:" , "<unnamed>" , "6379/TCP" } ,
{ "Endpoints:" } ,
{ "Session Affinity:" , "None" } }
checkOutput ( output , requiredStrings )
// Node
2015-12-10 14:35:58 +00:00
// It should be OK to list unschedulable Nodes here.
2015-12-10 09:39:03 +00:00
nodes , err := c . Nodes ( ) . List ( api . ListOptions { } )
2015-07-24 08:20:35 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2015-09-10 08:40:22 +00:00
node := nodes . Items [ 0 ]
2015-11-08 18:58:21 +00:00
output = runKubectlOrDie ( "describe" , "node" , node . Name )
2015-07-24 08:20:35 +00:00
requiredStrings = [ ] [ ] string {
{ "Name:" , node . Name } ,
{ "Labels:" } ,
{ "CreationTimestamp:" } ,
{ "Conditions:" } ,
{ "Type" , "Status" , "LastHeartbeatTime" , "LastTransitionTime" , "Reason" , "Message" } ,
{ "Addresses:" } ,
{ "Capacity:" } ,
{ "Version:" } ,
{ "Kernel Version:" } ,
{ "OS Image:" } ,
{ "Container Runtime Version:" } ,
{ "Kubelet Version:" } ,
{ "Kube-Proxy Version:" } ,
{ "Pods:" } }
checkOutput ( output , requiredStrings )
// Namespace
2015-11-08 18:58:21 +00:00
output = runKubectlOrDie ( "describe" , "namespace" , ns )
2015-07-24 08:20:35 +00:00
requiredStrings = [ ] [ ] string {
{ "Name:" , ns } ,
{ "Labels:" } ,
{ "Status:" , "Active" } }
checkOutput ( output , requiredStrings )
// Quota and limitrange are skipped for now.
2015-07-09 00:14:28 +00:00
} )
} )
2015-07-14 09:37:30 +00:00
Describe ( "Kubectl expose" , func ( ) {
2015-10-07 14:09:24 +00:00
It ( "should create services for rc [Conformance]" , func ( ) {
2015-07-14 09:37:30 +00:00
mkpath := func ( file string ) string {
return filepath . Join ( testContext . RepoRoot , "examples/guestbook-go" , file )
}
controllerJson := mkpath ( "redis-master-controller.json" )
nsFlag := fmt . Sprintf ( "--namespace=%v" , ns )
redisPort := 6379
By ( "creating Redis RC" )
2015-11-08 18:58:21 +00:00
runKubectlOrDie ( "create" , "-f" , controllerJson , nsFlag )
2015-07-14 09:37:30 +00:00
forEachPod ( c , ns , "app" , "redis" , func ( pod api . Pod ) {
lookForStringInLog ( ns , pod . Name , "redis-master" , "The server is now ready to accept connections" , podStartTimeout )
} )
validateService := func ( name string , servicePort int , timeout time . Duration ) {
2015-09-10 01:28:53 +00:00
err := wait . Poll ( poll , timeout , func ( ) ( bool , error ) {
2015-07-14 09:37:30 +00:00
endpoints , err := c . Endpoints ( ns ) . Get ( name )
2015-09-16 23:20:40 +00:00
if err != nil {
2015-09-10 01:28:53 +00:00
if apierrs . IsNotFound ( err ) {
err = nil
}
Logf ( "Get endpoints failed (interval %v): %v" , poll , err )
return false , err
2015-09-16 23:20:40 +00:00
}
2015-07-14 09:37:30 +00:00
2015-08-04 13:24:37 +00:00
uidToPort := getContainerPortsByPodUID ( endpoints )
2015-06-26 08:08:48 +00:00
if len ( uidToPort ) == 0 {
Logf ( "No endpoint found, retrying" )
2015-09-10 01:28:53 +00:00
return false , nil
2015-07-14 09:37:30 +00:00
}
2015-06-26 08:08:48 +00:00
if len ( uidToPort ) > 1 {
2015-09-16 23:20:40 +00:00
Fail ( "Too many endpoints found" )
2015-06-26 08:08:48 +00:00
}
for _ , port := range uidToPort {
2015-07-14 09:37:30 +00:00
if port [ 0 ] != redisPort {
Failf ( "Wrong endpoint port: %d" , port [ 0 ] )
}
}
2015-09-10 01:28:53 +00:00
return true , nil
} )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2015-07-14 09:37:30 +00:00
service , err := c . Services ( ns ) . Get ( name )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
if len ( service . Spec . Ports ) != 1 {
Failf ( "1 port is expected" )
}
port := service . Spec . Ports [ 0 ]
if port . Port != servicePort {
Failf ( "Wrong service port: %d" , port . Port )
}
2015-11-18 18:15:16 +00:00
if port . TargetPort . IntValue ( ) != redisPort {
2015-07-14 09:37:30 +00:00
Failf ( "Wrong target port: %d" )
}
}
By ( "exposing RC" )
2015-11-08 18:58:21 +00:00
runKubectlOrDie ( "expose" , "rc" , "redis-master" , "--name=rm2" , "--port=1234" , fmt . Sprintf ( "--target-port=%d" , redisPort ) , nsFlag )
2015-09-16 23:20:40 +00:00
waitForService ( c , ns , "rm2" , true , poll , serviceStartTimeout )
validateService ( "rm2" , 1234 , serviceStartTimeout )
2015-07-14 09:37:30 +00:00
By ( "exposing service" )
2015-11-08 18:58:21 +00:00
runKubectlOrDie ( "expose" , "service" , "rm2" , "--name=rm3" , "--port=2345" , fmt . Sprintf ( "--target-port=%d" , redisPort ) , nsFlag )
2015-09-16 23:20:40 +00:00
waitForService ( c , ns , "rm3" , true , poll , serviceStartTimeout )
validateService ( "rm3" , 2345 , serviceStartTimeout )
2015-07-14 09:37:30 +00:00
} )
} )
2015-07-24 08:20:35 +00:00
Describe ( "Kubectl label" , func ( ) {
var podPath string
var nsFlag string
BeforeEach ( func ( ) {
podPath = filepath . Join ( testContext . RepoRoot , "docs/user-guide/pod.yaml" )
By ( "creating the pod" )
nsFlag = fmt . Sprintf ( "--namespace=%v" , ns )
2015-11-08 18:58:21 +00:00
runKubectlOrDie ( "create" , "-f" , podPath , nsFlag )
2015-07-24 08:20:35 +00:00
checkPodsRunningReady ( c , ns , [ ] string { simplePodName } , podStartTimeout )
} )
AfterEach ( func ( ) {
cleanup ( podPath , ns , simplePodSelector )
} )
2015-10-07 14:09:24 +00:00
It ( "should update the label on a resource [Conformance]" , func ( ) {
2015-07-24 08:20:35 +00:00
labelName := "testing-label"
labelValue := "testing-label-value"
By ( "adding the label " + labelName + " with value " + labelValue + " to a pod" )
2015-11-08 18:58:21 +00:00
runKubectlOrDie ( "label" , "pods" , simplePodName , labelName + "=" + labelValue , nsFlag )
2015-07-24 08:20:35 +00:00
By ( "verifying the pod has the label " + labelName + " with the value " + labelValue )
2015-11-08 18:58:21 +00:00
output := runKubectlOrDie ( "get" , "pod" , simplePodName , "-L" , labelName , nsFlag )
2015-07-24 08:20:35 +00:00
if ! strings . Contains ( output , labelValue ) {
Failf ( "Failed updating label " + labelName + " to the pod " + simplePodName )
}
By ( "removing the label " + labelName + " of a pod" )
2015-11-08 18:58:21 +00:00
runKubectlOrDie ( "label" , "pods" , simplePodName , labelName + "-" , nsFlag )
2015-07-24 08:20:35 +00:00
By ( "verifying the pod doesn't have the label " + labelName )
2015-11-08 18:58:21 +00:00
output = runKubectlOrDie ( "get" , "pod" , simplePodName , "-L" , labelName , nsFlag )
2015-07-24 08:20:35 +00:00
if strings . Contains ( output , labelValue ) {
Failf ( "Failed removing label " + labelName + " of the pod " + simplePodName )
}
} )
} )
2015-07-13 12:06:00 +00:00
Describe ( "Kubectl logs" , func ( ) {
2015-09-10 03:46:11 +00:00
var rcPath string
var nsFlag string
containerName := "redis-master"
BeforeEach ( func ( ) {
2015-07-13 12:06:00 +00:00
mkpath := func ( file string ) string {
return filepath . Join ( testContext . RepoRoot , "examples/guestbook-go" , file )
}
2015-09-10 03:46:11 +00:00
rcPath = mkpath ( "redis-master-controller.json" )
By ( "creating an rc" )
nsFlag = fmt . Sprintf ( "--namespace=%v" , ns )
2015-11-08 18:58:21 +00:00
runKubectlOrDie ( "create" , "-f" , rcPath , nsFlag )
2015-09-10 03:46:11 +00:00
} )
AfterEach ( func ( ) {
cleanup ( rcPath , ns , simplePodSelector )
} )
2015-10-07 14:09:24 +00:00
It ( "should be able to retrieve and filter logs [Conformance]" , func ( ) {
2016-01-13 19:27:40 +00:00
SkipUnlessServerVersionGTE ( extendedPodLogFilterVersion , c )
2015-07-13 12:06:00 +00:00
forEachPod ( c , ns , "app" , "redis" , func ( pod api . Pod ) {
2015-09-10 03:46:11 +00:00
By ( "checking for a matching strings" )
_ , err := lookForStringInLog ( ns , pod . Name , containerName , "The server is now ready to accept connections" , podStartTimeout )
2015-07-13 12:06:00 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2015-09-10 03:46:11 +00:00
By ( "limiting log lines" )
2015-11-08 18:58:21 +00:00
out := runKubectlOrDie ( "log" , pod . Name , containerName , nsFlag , "--tail=1" )
2015-09-10 03:46:11 +00:00
Expect ( len ( out ) ) . NotTo ( BeZero ( ) )
Expect ( len ( strings . Split ( out , "\n" ) ) ) . To ( Equal ( 1 ) )
By ( "limiting log bytes" )
2015-11-08 18:58:21 +00:00
out = runKubectlOrDie ( "log" , pod . Name , containerName , nsFlag , "--limit-bytes=1" )
2015-09-10 03:46:11 +00:00
Expect ( len ( strings . Split ( out , "\n" ) ) ) . To ( Equal ( 1 ) )
Expect ( len ( out ) ) . To ( Equal ( 1 ) )
By ( "exposing timestamps" )
2015-11-08 18:58:21 +00:00
out = runKubectlOrDie ( "log" , pod . Name , containerName , nsFlag , "--tail=1" , "--timestamps" )
2015-09-10 03:46:11 +00:00
lines := strings . Split ( out , "\n" )
Expect ( len ( lines ) ) . To ( Equal ( 1 ) )
words := strings . Split ( lines [ 0 ] , " " )
Expect ( len ( words ) ) . To ( BeNumerically ( ">" , 1 ) )
if _ , err := time . Parse ( time . RFC3339Nano , words [ 0 ] ) ; err != nil {
if _ , err := time . Parse ( time . RFC3339 , words [ 0 ] ) ; err != nil {
Failf ( "expected %q to be RFC3339 or RFC3339Nano" , words [ 0 ] )
}
}
By ( "restricting to a time range" )
2016-01-28 23:35:49 +00:00
// Note: we must wait at least two seconds,
// because the granularity is only 1 second and
// it could end up rounding the wrong way.
time . Sleep ( 2500 * time . Millisecond ) // ensure that startup logs on the node are seen as older than 1s
2016-01-28 21:18:36 +00:00
recent_out := runKubectlOrDie ( "log" , pod . Name , containerName , nsFlag , "--since=1s" )
recent := len ( strings . Split ( recent_out , "\n" ) )
older_out := runKubectlOrDie ( "log" , pod . Name , containerName , nsFlag , "--since=24h" )
older := len ( strings . Split ( older_out , "\n" ) )
Expect ( recent ) . To ( BeNumerically ( "<" , older ) , "expected recent(%v) to be less than older(%v)\nrecent lines:\n%v\nolder lines:\n%v\n" , recent , older , recent_out , older_out )
2015-07-13 12:06:00 +00:00
} )
} )
} )
Describe ( "Kubectl patch" , func ( ) {
2015-10-07 14:09:24 +00:00
It ( "should add annotations for pods in rc [Conformance]" , func ( ) {
2015-07-13 12:06:00 +00:00
mkpath := func ( file string ) string {
return filepath . Join ( testContext . RepoRoot , "examples/guestbook-go" , file )
}
controllerJson := mkpath ( "redis-master-controller.json" )
nsFlag := fmt . Sprintf ( "--namespace=%v" , ns )
By ( "creating Redis RC" )
2015-11-08 18:58:21 +00:00
runKubectlOrDie ( "create" , "-f" , controllerJson , nsFlag )
2015-07-13 12:06:00 +00:00
By ( "patching all pods" )
forEachPod ( c , ns , "app" , "redis" , func ( pod api . Pod ) {
2015-11-08 18:58:21 +00:00
runKubectlOrDie ( "patch" , "pod" , pod . Name , nsFlag , "-p" , "{\"metadata\":{\"annotations\":{\"x\":\"y\"}}}" )
2015-07-13 12:06:00 +00:00
} )
By ( "checking annotations" )
forEachPod ( c , ns , "app" , "redis" , func ( pod api . Pod ) {
found := false
for key , val := range pod . Annotations {
if key == "x" && val == "y" {
found = true
}
}
if ! found {
2015-08-07 16:40:59 +00:00
Failf ( "Added annotation not found" )
2015-07-13 12:06:00 +00:00
}
} )
} )
} )
2015-07-23 12:15:15 +00:00
Describe ( "Kubectl version" , func ( ) {
2015-10-07 14:09:24 +00:00
It ( "should check is all data is printed [Conformance]" , func ( ) {
2015-11-08 18:58:21 +00:00
version := runKubectlOrDie ( "version" )
2015-07-23 12:15:15 +00:00
requiredItems := [ ] string { "Client Version:" , "Server Version:" , "Major:" , "Minor:" , "GitCommit:" }
for _ , item := range requiredItems {
if ! strings . Contains ( version , item ) {
Failf ( "Required item %s not found in %s" , item , version )
}
}
} )
} )
2015-07-09 18:26:48 +00:00
2015-08-04 19:54:17 +00:00
Describe ( "Kubectl run rc" , func ( ) {
2015-07-09 18:26:48 +00:00
var nsFlag string
var rcName string
BeforeEach ( func ( ) {
nsFlag = fmt . Sprintf ( "--namespace=%v" , ns )
rcName = "e2e-test-nginx-rc"
} )
AfterEach ( func ( ) {
2015-12-14 07:49:05 +00:00
runKubectlOrDie ( "delete" , "rc" , rcName , nsFlag )
2015-07-09 18:26:48 +00:00
} )
2015-10-07 14:09:24 +00:00
It ( "should create an rc from an image [Conformance]" , func ( ) {
2015-07-09 18:26:48 +00:00
image := "nginx"
By ( "running the image " + image )
2016-02-02 22:51:15 +00:00
runKubectlOrDie ( "run" , rcName , "--image=" + image , "--generator=run/v1" , nsFlag )
2015-07-09 18:26:48 +00:00
By ( "verifying the rc " + rcName + " was created" )
rc , err := c . ReplicationControllers ( ns ) . Get ( rcName )
if err != nil {
Failf ( "Failed getting rc %s: %v" , rcName , err )
}
containers := rc . Spec . Template . Spec . Containers
if containers == nil || len ( containers ) != 1 || containers [ 0 ] . Image != image {
Failf ( "Failed creating rc %s for 1 pod with expected image %s" , rcName , image )
}
By ( "verifying the pod controlled by rc " + rcName + " was created" )
label := labels . SelectorFromSet ( labels . Set ( map [ string ] string { "run" : rcName } ) )
podlist , err := waitForPodsWithLabel ( c , ns , label )
if err != nil {
Failf ( "Failed getting pod controlled by rc %s: %v" , rcName , err )
}
pods := podlist . Items
if pods == nil || len ( pods ) != 1 || len ( pods [ 0 ] . Spec . Containers ) != 1 || pods [ 0 ] . Spec . Containers [ 0 ] . Image != image {
2015-11-08 18:58:21 +00:00
runKubectlOrDie ( "get" , "pods" , "-L" , "run" , nsFlag )
2015-07-09 18:26:48 +00:00
Failf ( "Failed creating 1 pod with expected image %s. Number of pods = %v" , image , len ( pods ) )
}
} )
2015-07-07 05:09:22 +00:00
} )
2016-02-02 22:51:15 +00:00
Describe ( "Kubectl run deployment" , func ( ) {
var nsFlag string
var dName string
BeforeEach ( func ( ) {
nsFlag = fmt . Sprintf ( "--namespace=%v" , ns )
dName = "e2e-test-nginx-deployment"
} )
AfterEach ( func ( ) {
runKubectlOrDie ( "delete" , "deployment" , dName , nsFlag )
} )
It ( "should create a deployment from an image [Conformance]" , func ( ) {
image := "nginx"
By ( "running the image " + image )
runKubectlOrDie ( "run" , dName , "--image=" + image , nsFlag )
By ( "verifying the deployment " + dName + " was created" )
d , err := c . Extensions ( ) . Deployments ( ns ) . Get ( dName )
if err != nil {
Failf ( "Failed getting deployment %s: %v" , dName , err )
}
containers := d . Spec . Template . Spec . Containers
if containers == nil || len ( containers ) != 1 || containers [ 0 ] . Image != image {
Failf ( "Failed creating deployment %s for 1 pod with expected image %s" , dName , image )
}
By ( "verifying the pod controlled by deployment " + dName + " was created" )
label := labels . SelectorFromSet ( labels . Set ( map [ string ] string { "run" : dName } ) )
podlist , err := waitForPodsWithLabel ( c , ns , label )
if err != nil {
Failf ( "Failed getting pod controlled by deployment %s: %v" , dName , err )
}
pods := podlist . Items
if pods == nil || len ( pods ) != 1 || len ( pods [ 0 ] . Spec . Containers ) != 1 || pods [ 0 ] . Spec . Containers [ 0 ] . Image != image {
runKubectlOrDie ( "get" , "pods" , "-L" , "run" , nsFlag )
Failf ( "Failed creating 1 pod with expected image %s. Number of pods = %v" , image , len ( pods ) )
}
} )
} )
2015-11-13 01:07:21 +00:00
Describe ( "Kubectl run job" , func ( ) {
2015-08-04 19:54:17 +00:00
var nsFlag string
2015-11-13 01:07:21 +00:00
var jobName string
2015-08-04 19:54:17 +00:00
BeforeEach ( func ( ) {
nsFlag = fmt . Sprintf ( "--namespace=%v" , ns )
2015-11-13 01:07:21 +00:00
jobName = "e2e-test-nginx-job"
2015-08-04 19:54:17 +00:00
} )
AfterEach ( func ( ) {
2015-12-14 07:49:05 +00:00
runKubectlOrDie ( "delete" , "jobs" , jobName , nsFlag )
2015-08-04 19:54:17 +00:00
} )
2015-11-13 01:07:21 +00:00
It ( "should create a job from an image when restart is OnFailure [Conformance]" , func ( ) {
2016-01-13 19:27:40 +00:00
SkipUnlessServerVersionGTE ( jobsVersion , c )
2015-08-04 19:54:17 +00:00
image := "nginx"
By ( "running the image " + image )
2015-11-13 01:07:21 +00:00
runKubectlOrDie ( "run" , jobName , "--restart=OnFailure" , "--image=" + image , nsFlag )
By ( "verifying the job " + jobName + " was created" )
job , err := c . Extensions ( ) . Jobs ( ns ) . Get ( jobName )
2015-08-04 19:54:17 +00:00
if err != nil {
2015-11-13 01:07:21 +00:00
Failf ( "Failed getting job %s: %v" , jobName , err )
2015-08-04 19:54:17 +00:00
}
2015-11-13 01:07:21 +00:00
containers := job . Spec . Template . Spec . Containers
2015-08-04 19:54:17 +00:00
if containers == nil || len ( containers ) != 1 || containers [ 0 ] . Image != image {
2015-11-13 01:07:21 +00:00
Failf ( "Failed creating job %s for 1 pod with expected image %s" , jobName , image )
2015-08-04 19:54:17 +00:00
}
2015-11-13 01:07:21 +00:00
if job . Spec . Template . Spec . RestartPolicy != api . RestartPolicyOnFailure {
Failf ( "Failed creating a job with correct restart policy for --restart=OnFailure" )
2015-08-04 19:54:17 +00:00
}
} )
2015-11-13 01:07:21 +00:00
It ( "should create a job from an image when restart is Never [Conformance]" , func ( ) {
2016-01-13 19:27:40 +00:00
SkipUnlessServerVersionGTE ( jobsVersion , c )
2015-08-04 19:54:17 +00:00
image := "nginx"
By ( "running the image " + image )
2015-11-13 01:07:21 +00:00
runKubectlOrDie ( "run" , jobName , "--restart=Never" , "--image=" + image , nsFlag )
By ( "verifying the job " + jobName + " was created" )
job , err := c . Extensions ( ) . Jobs ( ns ) . Get ( jobName )
2015-08-04 19:54:17 +00:00
if err != nil {
2015-11-13 01:07:21 +00:00
Failf ( "Failed getting job %s: %v" , jobName , err )
2015-08-04 19:54:17 +00:00
}
2015-11-13 01:07:21 +00:00
containers := job . Spec . Template . Spec . Containers
2015-08-04 19:54:17 +00:00
if containers == nil || len ( containers ) != 1 || containers [ 0 ] . Image != image {
2015-11-13 01:07:21 +00:00
Failf ( "Failed creating job %s for 1 pod with expected image %s" , jobName , image )
2015-08-04 19:54:17 +00:00
}
2015-11-13 01:07:21 +00:00
if job . Spec . Template . Spec . RestartPolicy != api . RestartPolicyNever {
Failf ( "Failed creating a job with correct restart policy for --restart=OnFailure" )
2015-08-04 19:54:17 +00:00
}
} )
} )
2015-12-10 02:36:25 +00:00
Describe ( "Kubectl run --rm job" , func ( ) {
nsFlag := fmt . Sprintf ( "--namespace=%v" , ns )
jobName := "e2e-test-rm-busybox-job"
It ( "should create a job from an image, then delete the job [Conformance]" , func ( ) {
2016-01-13 19:27:40 +00:00
SkipUnlessServerVersionGTE ( jobsVersion , c )
2015-12-10 02:36:25 +00:00
By ( "executing a command with run --rm and attach with stdin" )
2016-01-08 16:14:55 +00:00
t := time . NewTimer ( runJobTimeout )
defer t . Stop ( )
2015-12-10 02:36:25 +00:00
runOutput := newKubectlCommand ( nsFlag , "run" , jobName , "--image=busybox" , "--rm=true" , "--restart=Never" , "--attach=true" , "--stdin" , "--" , "sh" , "-c" , "cat && echo 'stdin closed'" ) .
withStdinData ( "abcd1234" ) .
2016-01-08 16:14:55 +00:00
withTimeout ( t . C ) .
2015-12-10 02:36:25 +00:00
execOrDie ( )
Expect ( runOutput ) . To ( ContainSubstring ( "abcd1234" ) )
Expect ( runOutput ) . To ( ContainSubstring ( "stdin closed" ) )
By ( "verifying the job " + jobName + " was deleted" )
_ , err := c . Extensions ( ) . Jobs ( ns ) . Get ( jobName )
Expect ( err ) . To ( HaveOccurred ( ) )
Expect ( apierrs . IsNotFound ( err ) ) . To ( BeTrue ( ) )
} )
} )
2015-07-07 05:09:22 +00:00
Describe ( "Proxy server" , func ( ) {
// TODO: test proxy options (static, prefix, etc)
2015-10-07 14:09:24 +00:00
It ( "should support proxy with --port 0 [Conformance]" , func ( ) {
2015-07-07 05:09:22 +00:00
By ( "starting the proxy server" )
port , cmd , err := startProxyServer ( )
if cmd != nil {
defer tryKill ( cmd )
}
if err != nil {
Failf ( "Failed to start proxy server: %v" , err )
}
By ( "curling proxy /api/ output" )
localAddr := fmt . Sprintf ( "http://localhost:%d/api/" , port )
apiVersions , err := getAPIVersions ( localAddr )
2015-10-09 05:18:16 +00:00
if err != nil {
Failf ( "Expected at least one supported apiversion, got error %v" , err )
}
2015-07-07 05:09:22 +00:00
if len ( apiVersions . Versions ) < 1 {
Failf ( "Expected at least one supported apiversion, got %v" , apiVersions )
}
} )
2015-07-09 18:26:48 +00:00
2015-10-07 14:09:24 +00:00
It ( "should support --unix-socket=/path [Conformance]" , func ( ) {
2015-07-07 10:39:38 +00:00
By ( "Starting the proxy" )
tmpdir , err := ioutil . TempDir ( "" , "kubectl-proxy-unix" )
if err != nil {
Failf ( "Failed to create temporary directory: %v" , err )
}
path := filepath . Join ( tmpdir , "test" )
defer os . Remove ( path )
defer os . Remove ( tmpdir )
cmd := kubectlCmd ( "proxy" , fmt . Sprintf ( "--unix-socket=%s" , path ) )
stdout , stderr , err := startCmdAndStreamOutput ( cmd )
if err != nil {
Failf ( "Failed to start kubectl command: %v" , err )
}
defer stdout . Close ( )
defer stderr . Close ( )
defer tryKill ( cmd )
buf := make ( [ ] byte , 128 )
if _ , err = stdout . Read ( buf ) ; err != nil {
Failf ( "Expected output from kubectl proxy: %v" , err )
}
By ( "retrieving proxy /api/ output" )
_ , err = curlUnix ( "http://unused/api" , path )
if err != nil {
Failf ( "Failed get of /api at %s: %v" , path , err )
}
} )
} )
2015-02-20 17:35:42 +00:00
} )
2015-07-24 08:20:35 +00:00
// Checks whether the output split by line contains the required elements.
func checkOutput ( output string , required [ ] [ ] string ) {
outputLines := strings . Split ( output , "\n" )
currentLine := 0
for _ , requirement := range required {
for currentLine < len ( outputLines ) && ! strings . Contains ( outputLines [ currentLine ] , requirement [ 0 ] ) {
currentLine ++
}
if currentLine == len ( outputLines ) {
Failf ( "Failed to find %s in %s" , requirement [ 0 ] , output )
}
for _ , item := range requirement [ 1 : ] {
if ! strings . Contains ( outputLines [ currentLine ] , item ) {
Failf ( "Failed to find %s in %s" , item , outputLines [ currentLine ] )
}
}
}
}
2015-10-09 01:30:38 +00:00
func getAPIVersions ( apiEndpoint string ) ( * unversioned . APIVersions , error ) {
2015-07-07 05:09:22 +00:00
body , err := curl ( apiEndpoint )
if err != nil {
return nil , fmt . Errorf ( "Failed http.Get of %s: %v" , apiEndpoint , err )
}
2015-10-09 01:30:38 +00:00
var apiVersions unversioned . APIVersions
2015-07-07 05:09:22 +00:00
if err := json . Unmarshal ( [ ] byte ( body ) , & apiVersions ) ; err != nil {
return nil , fmt . Errorf ( "Failed to parse /api output %s: %v" , body , err )
}
return & apiVersions , nil
}
func startProxyServer ( ) ( int , * exec . Cmd , error ) {
// Specifying port 0 indicates we want the os to pick a random port.
cmd := kubectlCmd ( "proxy" , "-p" , "0" )
stdout , stderr , err := startCmdAndStreamOutput ( cmd )
if err != nil {
return - 1 , nil , err
}
defer stdout . Close ( )
defer stderr . Close ( )
buf := make ( [ ] byte , 128 )
var n int
if n , err = stdout . Read ( buf ) ; err != nil {
return - 1 , cmd , fmt . Errorf ( "Failed to read from kubectl proxy stdout: %v" , err )
}
output := string ( buf [ : n ] )
match := proxyRegexp . FindStringSubmatch ( output )
if len ( match ) == 2 {
if port , err := strconv . Atoi ( match [ 1 ] ) ; err == nil {
return port , cmd , nil
}
}
return - 1 , cmd , fmt . Errorf ( "Failed to parse port from proxy stdout: %s" , output )
}
2015-07-07 10:39:38 +00:00
func curlUnix ( url string , path string ) ( string , error ) {
dial := func ( proto , addr string ) ( net . Conn , error ) {
return net . Dial ( "unix" , path )
}
transport := & http . Transport {
Dial : dial ,
}
return curlTransport ( url , transport )
}
func curlTransport ( url string , transport * http . Transport ) ( string , error ) {
client := & http . Client { Transport : transport }
resp , err := client . Get ( url )
2015-06-30 16:43:37 +00:00
if err != nil {
return "" , err
}
defer resp . Body . Close ( )
body , err := ioutil . ReadAll ( resp . Body )
if err != nil {
return "" , err
}
return string ( body [ : ] ) , nil
}
2015-07-07 10:39:38 +00:00
func curl ( url string ) ( string , error ) {
return curlTransport ( url , & http . Transport { } )
}
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-10-07 20:08:47 +00:00
Logf ( "Failed to get response from guestbook. err: %v, response: %s" , err , res )
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" ) .
2015-08-10 18:00:44 +00:00
Suffix ( "/guestbook.php" ) .
2015-03-13 16:26:41 +00:00
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-09-10 21:32:57 +00:00
const applyTestLabel = "kubectl.kubernetes.io/apply-test"
func readBytesFromFile ( filename string ) [ ] byte {
file , err := os . Open ( filename )
if err != nil {
Failf ( err . Error ( ) )
}
data , err := ioutil . ReadAll ( file )
if err != nil {
Failf ( err . Error ( ) )
}
return data
}
func readReplicationControllerFromFile ( filename string ) * api . ReplicationController {
data := readBytesFromFile ( filename )
rc := api . ReplicationController { }
if err := yaml . Unmarshal ( data , & rc ) ; err != nil {
Failf ( err . Error ( ) )
}
return & rc
}
func modifyReplicationControllerConfiguration ( filename string ) io . Reader {
rc := readReplicationControllerFromFile ( filename )
rc . Labels [ applyTestLabel ] = "ADDED"
rc . Spec . Selector [ applyTestLabel ] = "ADDED"
rc . Spec . Template . Labels [ applyTestLabel ] = "ADDED"
data , err := json . Marshal ( rc )
if err != nil {
Failf ( "json marshal failed: %s\n" , err )
}
return bytes . NewReader ( data )
}
func forEachReplicationController ( c * client . Client , ns , selectorKey , selectorValue string , fn func ( api . ReplicationController ) ) {
var rcs * api . ReplicationControllerList
var err error
for t := time . Now ( ) ; time . Since ( t ) < podListTimeout ; time . Sleep ( poll ) {
2015-12-02 11:12:57 +00:00
label := labels . SelectorFromSet ( labels . Set ( map [ string ] string { selectorKey : selectorValue } ) )
2015-12-10 09:39:03 +00:00
options := api . ListOptions { LabelSelector : label }
2015-12-02 11:12:57 +00:00
rcs , err = c . ReplicationControllers ( ns ) . List ( options )
2015-09-10 21:32:57 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
if len ( rcs . Items ) > 0 {
break
}
}
if rcs == nil || len ( rcs . Items ) == 0 {
Failf ( "No replication controllers found" )
}
for _ , rc := range rcs . Items {
fn ( rc )
}
}
func validateReplicationControllerConfiguration ( rc api . ReplicationController ) {
if rc . Name == "redis-master" {
if _ , ok := rc . Annotations [ kubectl . LastAppliedConfigAnnotation ] ; ! ok {
Failf ( "Annotation not found in modified configuration:\n%v\n" , rc )
}
if value , ok := rc . Labels [ applyTestLabel ] ; ! ok || value != "ADDED" {
Failf ( "Added label %s not found in modified configuration:\n%v\n" , applyTestLabel , rc )
}
}
}
2015-03-26 20:34:18 +00:00
// getUDData creates a validator function based on the input string (i.e. kitten.jpg).
2015-10-20 02:41:58 +00:00
// For example, if you send "kitten.jpg", this function verifies that the image jpg = kitten.jpg
2015-03-26 20:34:18 +00:00
// 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 )
2015-12-16 19:18:47 +00:00
subResourceProxyAvailable , err := serverVersionGTE ( subResourceProxyVersion , c )
if err != nil {
return err
}
var body [ ] byte
if subResourceProxyAvailable {
body , err = c . Get ( ) .
Namespace ( ns ) .
Resource ( "pods" ) .
SubResource ( "proxy" ) .
Name ( podID ) .
Suffix ( "data.json" ) .
Do ( ) .
Raw ( )
} else {
body , err = c . Get ( ) .
Prefix ( "proxy" ) .
Namespace ( ns ) .
Resource ( "pods" ) .
Name ( podID ) .
Suffix ( "data.json" ) .
Do ( ) .
Raw ( )
}
2015-03-26 20:34:18 +00:00
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 {
2015-08-20 02:09:57 +00:00
return errors . New ( fmt . Sprintf ( "data served up in container is inaccurate, %s didn't contain %s" , data , jpgExpected ) )
2015-03-26 19:22:04 +00:00
}
}
2015-02-20 17:35:42 +00:00
}
2015-08-31 17:23:47 +00:00
// newBlockingReader returns a reader that allows reading the given string,
// then blocks until Close() is called on the returned closer.
//
// We're explicitly returning the reader and closer separately, because
// the closer needs to be the *os.File we get from os.Pipe(). This is required
// so the exec of kubectl can pass the underlying file descriptor to the exec
// syscall, instead of creating another os.Pipe and blocking on the io.Copy
// between the source (e.g. stdin) and the write half of the pipe.
func newBlockingReader ( s string ) ( io . Reader , io . Closer , error ) {
r , w , err := os . Pipe ( )
if err != nil {
return nil , nil , err
}
w . Write ( [ ] byte ( s ) )
return r , w , nil
}
2015-09-17 20:11:27 +00:00
// newStreamingUpload creates a new http.Request that will stream POST
// a file to a URI.
func newStreamingUpload ( filePath string ) ( * io . PipeReader , * multipart . Writer , error ) {
file , err := os . Open ( filePath )
if err != nil {
return nil , nil , err
}
r , w := io . Pipe ( )
postBodyWriter := multipart . NewWriter ( w )
go streamingUpload ( file , filepath . Base ( filePath ) , postBodyWriter , w )
return r , postBodyWriter , err
}
// streamingUpload streams a file via a pipe through a multipart.Writer.
// Generally one should use newStreamingUpload instead of calling this directly.
func streamingUpload ( file * os . File , fileName string , postBodyWriter * multipart . Writer , w * io . PipeWriter ) {
defer GinkgoRecover ( )
defer file . Close ( )
defer w . Close ( )
// Set up the form file
fileWriter , err := postBodyWriter . CreateFormFile ( "file" , fileName )
if err != nil {
Failf ( "Unable to to write file at %s to buffer. Error: %s" , fileName , err )
}
// Copy kubectl binary into the file writer
if _ , err := io . Copy ( fileWriter , file ) ; err != nil {
Failf ( "Unable to to copy file at %s into the file writer. Error: %s" , fileName , err )
}
// Nothing more should be written to this instance of the postBodyWriter
if err := postBodyWriter . Close ( ) ; err != nil {
Failf ( "Unable to close the writer for file upload. Error: %s" , err )
}
}
2015-11-02 17:58:50 +00:00
var binPrefixes = [ ] string {
"_output/dockerized/bin" ,
"_output/local/bin" ,
"platforms" ,
}
// findBinary searches through likely paths to find the specified binary. It
// takes the one that has been built most recently. Platform should be
// specified as '<os>/<arch>'. For example: 'linux/amd64'.
func findBinary ( binName string , platform string ) ( string , error ) {
var binTime time . Time
var binPath string
for _ , pre := range binPrefixes {
tryPath := path . Join ( testContext . RepoRoot , pre , platform , binName )
fi , err := os . Stat ( tryPath )
if err != nil {
continue
}
if fi . ModTime ( ) . After ( binTime ) {
binPath = tryPath
binTime = fi . ModTime ( )
}
}
if len ( binPath ) > 0 {
return binPath , nil
}
return binPath , fmt . Errorf ( "Could not find %v for %v" , binName , platform )
}