2015-06-15 14:31:17 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2015 The Kubernetes Authors .
2015-06-15 14:31:17 +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 .
* /
2017-07-18 20:04:46 +00:00
package lifecycle
2015-06-15 14:31:17 +00:00
import (
"bytes"
"fmt"
"io"
"os"
"strings"
"time"
2015-08-05 22:05:17 +00:00
"golang.org/x/crypto/ssh"
2017-01-11 14:09:48 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2017-02-25 00:44:21 +00:00
"k8s.io/apimachinery/pkg/labels"
2017-06-23 20:56:37 +00:00
clientset "k8s.io/client-go/kubernetes"
2016-04-07 17:21:31 +00:00
"k8s.io/kubernetes/test/e2e/framework"
2019-05-07 07:21:44 +00:00
e2elog "k8s.io/kubernetes/test/e2e/framework/log"
2019-05-01 16:53:13 +00:00
e2essh "k8s.io/kubernetes/test/e2e/framework/ssh"
2015-06-15 14:31:17 +00:00
2019-04-25 15:40:22 +00:00
"github.com/onsi/ginkgo"
"github.com/onsi/gomega"
2017-08-29 08:32:08 +00:00
imageutils "k8s.io/kubernetes/test/utils/image"
2015-06-15 14:31:17 +00:00
)
// TODO: it would probably be slightly better to build up the objects
// in the code and then serialize to yaml.
2019-04-25 15:40:22 +00:00
var reconcileAddonController = `
2015-06-23 14:03:47 +00:00
apiVersion : v1
2015-06-15 14:31:17 +00:00
kind : ReplicationController
metadata :
2017-02-25 00:44:21 +00:00
name : addon - reconcile - test
2015-07-01 13:57:39 +00:00
namespace : % s
2015-06-15 14:31:17 +00:00
labels :
2017-02-25 00:44:21 +00:00
k8s - app : addon - reconcile - test
2015-06-15 14:31:17 +00:00
kubernetes . io / cluster - service : "true"
2017-02-25 00:44:21 +00:00
addonmanager . kubernetes . io / mode : Reconcile
2015-06-15 14:31:17 +00:00
spec :
replicas : 2
selector :
2017-02-25 00:44:21 +00:00
k8s - app : addon - reconcile - test
2015-06-15 14:31:17 +00:00
template :
metadata :
labels :
2017-02-25 00:44:21 +00:00
k8s - app : addon - reconcile - test
2015-06-15 14:31:17 +00:00
spec :
containers :
2017-08-29 08:32:08 +00:00
- image : % s
2017-02-25 00:44:21 +00:00
name : addon - reconcile - test
2015-06-15 14:31:17 +00:00
ports :
- containerPort : 9376
protocol : TCP
`
2017-02-25 00:44:21 +00:00
// Should update "reconcile" class addon.
2019-04-25 15:40:22 +00:00
var reconcileAddonControllerUpdated = `
2015-06-23 14:03:47 +00:00
apiVersion : v1
2015-06-15 14:31:17 +00:00
kind : ReplicationController
metadata :
2017-02-25 00:44:21 +00:00
name : addon - reconcile - test
2015-07-01 13:57:39 +00:00
namespace : % s
2015-06-15 14:31:17 +00:00
labels :
2017-02-25 00:44:21 +00:00
k8s - app : addon - reconcile - test
2015-06-15 14:31:17 +00:00
kubernetes . io / cluster - service : "true"
2017-02-25 00:44:21 +00:00
addonmanager . kubernetes . io / mode : Reconcile
newLabel : addon - reconcile - test
2015-06-15 14:31:17 +00:00
spec :
replicas : 2
selector :
2017-02-25 00:44:21 +00:00
k8s - app : addon - reconcile - test
2015-06-15 14:31:17 +00:00
template :
metadata :
labels :
2017-02-25 00:44:21 +00:00
k8s - app : addon - reconcile - test
2015-06-15 14:31:17 +00:00
spec :
containers :
2017-08-29 08:32:08 +00:00
- image : % s
2017-02-25 00:44:21 +00:00
name : addon - reconcile - test
2015-06-15 14:31:17 +00:00
ports :
- containerPort : 9376
protocol : TCP
`
2019-04-25 15:40:22 +00:00
var ensureExistsAddonService = `
2015-06-23 14:03:47 +00:00
apiVersion : v1
2015-06-15 14:31:17 +00:00
kind : Service
metadata :
2017-02-25 00:44:21 +00:00
name : addon - ensure - exists - test
2015-07-01 13:57:39 +00:00
namespace : % s
2015-06-15 14:31:17 +00:00
labels :
2017-02-25 00:44:21 +00:00
k8s - app : addon - ensure - exists - test
addonmanager . kubernetes . io / mode : EnsureExists
2015-06-15 14:31:17 +00:00
spec :
ports :
- port : 9376
protocol : TCP
targetPort : 9376
selector :
2017-02-25 00:44:21 +00:00
k8s - app : addon - ensure - exists - test
2015-06-15 14:31:17 +00:00
`
2017-02-25 00:44:21 +00:00
// Should create but don't update "ensure exist" class addon.
2019-04-25 15:40:22 +00:00
var ensureExistsAddonServiceUpdated = `
2015-06-23 14:03:47 +00:00
apiVersion : v1
2015-06-15 14:31:17 +00:00
kind : Service
metadata :
2017-02-25 00:44:21 +00:00
name : addon - ensure - exists - test
2015-07-01 13:57:39 +00:00
namespace : % s
2015-06-15 14:31:17 +00:00
labels :
2017-02-25 00:44:21 +00:00
k8s - app : addon - ensure - exists - test
addonmanager . kubernetes . io / mode : EnsureExists
newLabel : addon - ensure - exists - test
2015-06-15 14:31:17 +00:00
spec :
ports :
- port : 9376
protocol : TCP
targetPort : 9376
selector :
2017-02-25 00:44:21 +00:00
k8s - app : addon - ensure - exists - test
2015-06-15 14:31:17 +00:00
`
2019-04-25 15:40:22 +00:00
var deprecatedLabelAddonService = `
2015-06-23 14:03:47 +00:00
apiVersion : v1
2017-02-25 00:44:21 +00:00
kind : Service
2015-06-15 14:31:17 +00:00
metadata :
2017-02-25 00:44:21 +00:00
name : addon - deprecated - label - test
2015-07-01 13:57:39 +00:00
namespace : % s
2015-06-15 14:31:17 +00:00
labels :
2017-02-25 00:44:21 +00:00
k8s - app : addon - deprecated - label - test
kubernetes . io / cluster - service : "true"
2015-06-15 14:31:17 +00:00
spec :
2017-02-25 00:44:21 +00:00
ports :
- port : 9376
protocol : TCP
targetPort : 9376
2015-06-15 14:31:17 +00:00
selector :
2017-02-25 00:44:21 +00:00
k8s - app : addon - deprecated - label - test
2015-06-15 14:31:17 +00:00
`
2017-02-25 00:44:21 +00:00
// Should update addon with label "kubernetes.io/cluster-service=true".
2019-04-25 15:40:22 +00:00
var deprecatedLabelAddonServiceUpdated = `
2015-06-23 14:03:47 +00:00
apiVersion : v1
2015-06-15 14:31:17 +00:00
kind : Service
metadata :
2017-02-25 00:44:21 +00:00
name : addon - deprecated - label - test
2015-07-01 13:57:39 +00:00
namespace : % s
2015-06-15 14:31:17 +00:00
labels :
2017-02-25 00:44:21 +00:00
k8s - app : addon - deprecated - label - test
kubernetes . io / cluster - service : "true"
newLabel : addon - deprecated - label - test
2015-06-15 14:31:17 +00:00
spec :
ports :
2017-02-25 00:44:21 +00:00
- port : 9376
2015-06-15 14:31:17 +00:00
protocol : TCP
targetPort : 9376
selector :
2017-02-25 00:44:21 +00:00
k8s - app : addon - deprecated - label - test
2015-06-15 14:31:17 +00:00
`
2017-02-25 00:44:21 +00:00
// Should not create addon without valid label.
2019-04-25 15:40:22 +00:00
var invalidAddonController = `
2016-11-04 23:37:58 +00:00
apiVersion : v1
2017-02-25 00:44:21 +00:00
kind : ReplicationController
2016-11-04 23:37:58 +00:00
metadata :
2017-02-25 00:44:21 +00:00
name : invalid - addon - test
2016-11-04 23:37:58 +00:00
namespace : % s
labels :
2017-02-25 00:44:21 +00:00
k8s - app : invalid - addon - test
addonmanager . kubernetes . io / mode : NotMatch
2016-11-04 23:37:58 +00:00
spec :
2017-02-25 00:44:21 +00:00
replicas : 2
2016-11-04 23:37:58 +00:00
selector :
k8s - app : invalid - addon - test
2017-02-25 00:44:21 +00:00
template :
metadata :
labels :
k8s - app : invalid - addon - test
spec :
containers :
2017-08-29 08:32:08 +00:00
- image : % s
2017-02-25 00:44:21 +00:00
name : invalid - addon - test
ports :
- containerPort : 9376
protocol : TCP
2016-11-04 23:37:58 +00:00
`
const (
addonTestPollInterval = 3 * time . Second
addonTestPollTimeout = 5 * time . Minute
2017-02-25 00:44:21 +00:00
addonNsName = metav1 . NamespaceSystem
2016-11-04 23:37:58 +00:00
)
2015-06-15 14:31:17 +00:00
2017-08-29 08:32:08 +00:00
var serveHostnameImage = imageutils . GetE2EImage ( imageutils . ServeHostname )
2015-06-15 14:31:17 +00:00
type stringPair struct {
data , fileName string
}
2017-07-18 20:04:46 +00:00
var _ = SIGDescribe ( "Addon update" , func ( ) {
2015-06-15 14:31:17 +00:00
var dir string
var sshClient * ssh . Client
2016-04-07 17:21:31 +00:00
f := framework . NewDefaultFramework ( "addon-update-test" )
2015-06-15 14:31:17 +00:00
2019-04-25 15:40:22 +00:00
ginkgo . BeforeEach ( func ( ) {
2015-07-20 21:10:48 +00:00
// This test requires:
2015-07-24 13:46:38 +00:00
// - SSH master access
2015-07-20 21:10:48 +00:00
// ... so the provider check should be identical to the intersection of
// providers that provide those capabilities.
2016-04-07 17:21:31 +00:00
if ! framework . ProviderIs ( "gce" ) {
2015-06-18 17:27:08 +00:00
return
}
2015-06-15 14:31:17 +00:00
2015-07-24 13:46:38 +00:00
var err error
2015-07-20 21:10:48 +00:00
sshClient , err = getMasterSSHClient ( )
2019-04-25 15:40:22 +00:00
gomega . Expect ( err ) . NotTo ( gomega . HaveOccurred ( ) , "Failed to get the master SSH client." )
2015-06-15 14:31:17 +00:00
} )
2019-04-25 15:40:22 +00:00
ginkgo . AfterEach ( func ( ) {
2015-06-15 14:31:17 +00:00
if sshClient != nil {
sshClient . Close ( )
}
} )
// WARNING: the test is not parallel-friendly!
2019-04-25 15:40:22 +00:00
ginkgo . It ( "should propagate add-on file changes [Slow]" , func ( ) {
2015-07-20 21:10:48 +00:00
// This test requires:
// - SSH
// - master access
// ... so the provider check should be identical to the intersection of
// providers that provide those capabilities.
2016-04-07 17:21:31 +00:00
framework . SkipUnlessProviderIs ( "gce" )
2015-06-15 14:31:17 +00:00
2015-06-18 17:27:08 +00:00
//these tests are long, so I squeezed several cases in one scenario
2019-04-25 15:40:22 +00:00
gomega . Expect ( sshClient ) . NotTo ( gomega . BeNil ( ) )
2015-07-24 13:46:38 +00:00
dir = f . Namespace . Name // we use it only to give a unique string for each test execution
2015-06-18 17:27:08 +00:00
2015-06-15 14:31:17 +00:00
temporaryRemotePathPrefix := "addon-test-dir"
temporaryRemotePath := temporaryRemotePathPrefix + "/" + dir // in home directory on kubernetes-master
defer sshExec ( sshClient , fmt . Sprintf ( "rm -rf %s" , temporaryRemotePathPrefix ) ) // ignore the result in cleanup
sshExecAndVerify ( sshClient , fmt . Sprintf ( "mkdir -p %s" , temporaryRemotePath ) )
2017-02-25 00:44:21 +00:00
rcAddonReconcile := "addon-reconcile-controller.yaml"
rcAddonReconcileUpdated := "addon-reconcile-controller-Updated.yaml"
rcInvalid := "invalid-addon-controller.yaml"
2015-06-15 14:31:17 +00:00
2017-02-25 00:44:21 +00:00
svcAddonDeprecatedLabel := "addon-deprecated-label-service.yaml"
svcAddonDeprecatedLabelUpdated := "addon-deprecated-label-service-updated.yaml"
svcAddonEnsureExists := "addon-ensure-exists-service.yaml"
svcAddonEnsureExistsUpdated := "addon-ensure-exists-service-updated.yaml"
2015-06-15 14:31:17 +00:00
var remoteFiles [ ] stringPair = [ ] stringPair {
2019-04-25 15:40:22 +00:00
{ fmt . Sprintf ( reconcileAddonController , addonNsName , serveHostnameImage ) , rcAddonReconcile } ,
{ fmt . Sprintf ( reconcileAddonControllerUpdated , addonNsName , serveHostnameImage ) , rcAddonReconcileUpdated } ,
{ fmt . Sprintf ( deprecatedLabelAddonService , addonNsName ) , svcAddonDeprecatedLabel } ,
{ fmt . Sprintf ( deprecatedLabelAddonServiceUpdated , addonNsName ) , svcAddonDeprecatedLabelUpdated } ,
{ fmt . Sprintf ( ensureExistsAddonService , addonNsName ) , svcAddonEnsureExists } ,
{ fmt . Sprintf ( ensureExistsAddonServiceUpdated , addonNsName ) , svcAddonEnsureExistsUpdated } ,
{ fmt . Sprintf ( invalidAddonController , addonNsName , serveHostnameImage ) , rcInvalid } ,
2015-06-15 14:31:17 +00:00
}
for _ , p := range remoteFiles {
err := writeRemoteFile ( sshClient , p . data , temporaryRemotePath , p . fileName , 0644 )
2019-04-25 15:40:22 +00:00
gomega . Expect ( err ) . NotTo ( gomega . HaveOccurred ( ) , "Failed to write file %q at remote path %q with ssh client %+v" , p . fileName , temporaryRemotePath , sshClient )
2015-06-15 14:31:17 +00:00
}
// directory on kubernetes-master
destinationDirPrefix := "/etc/kubernetes/addons/addon-test-dir"
destinationDir := destinationDirPrefix + "/" + dir
// cleanup from previous tests
_ , _ , _ , err := sshExec ( sshClient , fmt . Sprintf ( "sudo rm -rf %s" , destinationDirPrefix ) )
2019-04-25 15:40:22 +00:00
gomega . Expect ( err ) . NotTo ( gomega . HaveOccurred ( ) , "Failed to remove remote dir %q with ssh client %+v" , destinationDirPrefix , sshClient )
2015-06-15 14:31:17 +00:00
defer sshExec ( sshClient , fmt . Sprintf ( "sudo rm -rf %s" , destinationDirPrefix ) ) // ignore result in cleanup
sshExecAndVerify ( sshClient , fmt . Sprintf ( "sudo mkdir -p %s" , destinationDir ) )
2019-04-25 15:40:22 +00:00
ginkgo . By ( "copy invalid manifests to the destination dir" )
2015-06-15 14:31:17 +00:00
sshExecAndVerify ( sshClient , fmt . Sprintf ( "sudo cp %s/%s %s/%s" , temporaryRemotePath , rcInvalid , destinationDir , rcInvalid ) )
// we will verify at the end of the test that the objects weren't created from the invalid manifests
2019-04-25 15:40:22 +00:00
ginkgo . By ( "copy new manifests" )
2017-02-25 00:44:21 +00:00
sshExecAndVerify ( sshClient , fmt . Sprintf ( "sudo cp %s/%s %s/%s" , temporaryRemotePath , rcAddonReconcile , destinationDir , rcAddonReconcile ) )
sshExecAndVerify ( sshClient , fmt . Sprintf ( "sudo cp %s/%s %s/%s" , temporaryRemotePath , svcAddonDeprecatedLabel , destinationDir , svcAddonDeprecatedLabel ) )
sshExecAndVerify ( sshClient , fmt . Sprintf ( "sudo cp %s/%s %s/%s" , temporaryRemotePath , svcAddonEnsureExists , destinationDir , svcAddonEnsureExists ) )
// Delete the "ensure exist class" addon at the end.
defer func ( ) {
2019-05-07 07:21:44 +00:00
e2elog . Logf ( "Cleaning up ensure exist class addon." )
2019-04-25 15:40:22 +00:00
gomega . Expect ( f . ClientSet . CoreV1 ( ) . Services ( addonNsName ) . Delete ( "addon-ensure-exists-test" , nil ) ) . NotTo ( gomega . HaveOccurred ( ) )
2017-02-25 00:44:21 +00:00
} ( )
waitForReplicationControllerInAddonTest ( f . ClientSet , addonNsName , "addon-reconcile-test" , true )
waitForServiceInAddonTest ( f . ClientSet , addonNsName , "addon-deprecated-label-test" , true )
waitForServiceInAddonTest ( f . ClientSet , addonNsName , "addon-ensure-exists-test" , true )
// Replace the manifests with new contents.
2019-04-25 15:40:22 +00:00
ginkgo . By ( "update manifests" )
2017-02-25 00:44:21 +00:00
sshExecAndVerify ( sshClient , fmt . Sprintf ( "sudo cp %s/%s %s/%s" , temporaryRemotePath , rcAddonReconcileUpdated , destinationDir , rcAddonReconcile ) )
sshExecAndVerify ( sshClient , fmt . Sprintf ( "sudo cp %s/%s %s/%s" , temporaryRemotePath , svcAddonDeprecatedLabelUpdated , destinationDir , svcAddonDeprecatedLabel ) )
sshExecAndVerify ( sshClient , fmt . Sprintf ( "sudo cp %s/%s %s/%s" , temporaryRemotePath , svcAddonEnsureExistsUpdated , destinationDir , svcAddonEnsureExists ) )
// Wait for updated addons to have the new added label.
reconcileSelector := labels . SelectorFromSet ( labels . Set ( map [ string ] string { "newLabel" : "addon-reconcile-test" } ) )
waitForReplicationControllerwithSelectorInAddonTest ( f . ClientSet , addonNsName , true , reconcileSelector )
deprecatedLabelSelector := labels . SelectorFromSet ( labels . Set ( map [ string ] string { "newLabel" : "addon-deprecated-label-test" } ) )
waitForServicewithSelectorInAddonTest ( f . ClientSet , addonNsName , true , deprecatedLabelSelector )
// "Ensure exist class" addon should not be updated.
ensureExistSelector := labels . SelectorFromSet ( labels . Set ( map [ string ] string { "newLabel" : "addon-ensure-exists-test" } ) )
waitForServicewithSelectorInAddonTest ( f . ClientSet , addonNsName , false , ensureExistSelector )
2015-06-15 14:31:17 +00:00
2019-04-25 15:40:22 +00:00
ginkgo . By ( "remove manifests" )
2017-02-25 00:44:21 +00:00
sshExecAndVerify ( sshClient , fmt . Sprintf ( "sudo rm %s/%s" , destinationDir , rcAddonReconcile ) )
sshExecAndVerify ( sshClient , fmt . Sprintf ( "sudo rm %s/%s" , destinationDir , svcAddonDeprecatedLabel ) )
sshExecAndVerify ( sshClient , fmt . Sprintf ( "sudo rm %s/%s" , destinationDir , svcAddonEnsureExists ) )
2015-06-15 14:31:17 +00:00
2017-02-25 00:44:21 +00:00
waitForReplicationControllerInAddonTest ( f . ClientSet , addonNsName , "addon-reconcile-test" , false )
waitForServiceInAddonTest ( f . ClientSet , addonNsName , "addon-deprecated-label-test" , false )
// "Ensure exist class" addon will not be deleted when manifest is removed.
waitForServiceInAddonTest ( f . ClientSet , addonNsName , "addon-ensure-exists-test" , true )
2015-06-15 14:31:17 +00:00
2019-04-25 15:40:22 +00:00
ginkgo . By ( "verify invalid addons weren't created" )
2017-10-25 15:54:32 +00:00
_ , err = f . ClientSet . CoreV1 ( ) . ReplicationControllers ( addonNsName ) . Get ( "invalid-addon-test" , metav1 . GetOptions { } )
2019-04-25 15:40:22 +00:00
gomega . Expect ( err ) . To ( gomega . HaveOccurred ( ) )
2015-06-15 14:31:17 +00:00
2017-02-25 00:44:21 +00:00
// Invalid addon manifests and the "ensure exist class" addon will be deleted by the deferred function.
2015-06-15 14:31:17 +00:00
} )
} )
2016-10-18 13:00:38 +00:00
func waitForServiceInAddonTest ( c clientset . Interface , addonNamespace , name string , exist bool ) {
2016-04-07 17:21:31 +00:00
framework . ExpectNoError ( framework . WaitForService ( c , addonNamespace , name , exist , addonTestPollInterval , addonTestPollTimeout ) )
2015-06-15 14:31:17 +00:00
}
2016-10-18 13:00:38 +00:00
func waitForReplicationControllerInAddonTest ( c clientset . Interface , addonNamespace , name string , exist bool ) {
2016-04-07 17:21:31 +00:00
framework . ExpectNoError ( framework . WaitForReplicationController ( c , addonNamespace , name , exist , addonTestPollInterval , addonTestPollTimeout ) )
2015-06-15 14:31:17 +00:00
}
2017-02-25 00:44:21 +00:00
func waitForServicewithSelectorInAddonTest ( c clientset . Interface , addonNamespace string , exist bool , selector labels . Selector ) {
framework . ExpectNoError ( framework . WaitForServiceWithSelector ( c , addonNamespace , selector , exist , addonTestPollInterval , addonTestPollTimeout ) )
}
func waitForReplicationControllerwithSelectorInAddonTest ( c clientset . Interface , addonNamespace string , exist bool , selector labels . Selector ) {
framework . ExpectNoError ( framework . WaitForReplicationControllerwithSelector ( c , addonNamespace , selector , exist , addonTestPollInterval ,
addonTestPollTimeout ) )
}
2019-05-01 16:53:13 +00:00
// TODO use the ssh.SSH code, either adding an SCP to it or copying files
2016-04-21 22:01:26 +00:00
// differently.
2015-07-20 21:10:48 +00:00
func getMasterSSHClient ( ) ( * ssh . Client , error ) {
2015-06-15 14:31:17 +00:00
// Get a signer for the provider.
2019-05-01 16:53:13 +00:00
signer , err := e2essh . GetSigner ( framework . TestContext . Provider )
2015-06-15 14:31:17 +00:00
if err != nil {
2016-04-07 17:21:31 +00:00
return nil , fmt . Errorf ( "error getting signer for provider %s: '%v'" , framework . TestContext . Provider , err )
2015-06-15 14:31:17 +00:00
}
2016-04-21 22:01:26 +00:00
sshUser := os . Getenv ( "KUBE_SSH_USER" )
if sshUser == "" {
sshUser = os . Getenv ( "USER" )
}
2015-06-15 14:31:17 +00:00
config := & ssh . ClientConfig {
2017-09-05 19:38:57 +00:00
User : sshUser ,
Auth : [ ] ssh . AuthMethod { ssh . PublicKeys ( signer ) } ,
HostKeyCallback : ssh . InsecureIgnoreHostKey ( ) ,
2015-06-15 14:31:17 +00:00
}
2016-04-07 17:21:31 +00:00
host := framework . GetMasterHost ( ) + ":22"
2015-06-15 14:31:17 +00:00
client , err := ssh . Dial ( "tcp" , host , config )
if err != nil {
return nil , fmt . Errorf ( "error getting SSH client to host %s: '%v'" , host , err )
}
return client , err
}
func sshExecAndVerify ( client * ssh . Client , cmd string ) {
_ , _ , rc , err := sshExec ( client , cmd )
2019-04-25 15:40:22 +00:00
gomega . Expect ( err ) . NotTo ( gomega . HaveOccurred ( ) , "Failed to execute %q with ssh client %+v" , cmd , client )
gomega . Expect ( rc ) . To ( gomega . Equal ( 0 ) , "error return code from executing command on the cluster: %s" , cmd )
2015-06-15 14:31:17 +00:00
}
func sshExec ( client * ssh . Client , cmd string ) ( string , string , int , error ) {
2019-05-07 07:21:44 +00:00
e2elog . Logf ( "Executing '%s' on %v" , cmd , client . RemoteAddr ( ) )
2015-06-15 14:31:17 +00:00
session , err := client . NewSession ( )
if err != nil {
return "" , "" , 0 , fmt . Errorf ( "error creating session to host %s: '%v'" , client . RemoteAddr ( ) , err )
}
defer session . Close ( )
// Run the command.
code := 0
var bout , berr bytes . Buffer
session . Stdout , session . Stderr = & bout , & berr
err = session . Run ( cmd )
if err != nil {
// Check whether the command failed to run or didn't complete.
if exiterr , ok := err . ( * ssh . ExitError ) ; ok {
// If we got an ExitError and the exit code is nonzero, we'll
// consider the SSH itself successful (just that the command run
// errored on the host).
if code = exiterr . ExitStatus ( ) ; code != 0 {
err = nil
}
} else {
// Some other kind of error happened (e.g. an IOError); consider the
// SSH unsuccessful.
err = fmt . Errorf ( "failed running `%s` on %s: '%v'" , cmd , client . RemoteAddr ( ) , err )
}
}
return bout . String ( ) , berr . String ( ) , code , err
}
func writeRemoteFile ( sshClient * ssh . Client , data , dir , fileName string , mode os . FileMode ) error {
2019-05-07 07:21:44 +00:00
e2elog . Logf ( fmt . Sprintf ( "Writing remote file '%s/%s' on %v" , dir , fileName , sshClient . RemoteAddr ( ) ) )
2015-06-15 14:31:17 +00:00
session , err := sshClient . NewSession ( )
if err != nil {
return fmt . Errorf ( "error creating session to host %s: '%v'" , sshClient . RemoteAddr ( ) , err )
}
defer session . Close ( )
fileSize := len ( data )
2016-01-22 21:54:56 +00:00
pipe , err := session . StdinPipe ( )
if err != nil {
return err
}
defer pipe . Close ( )
if err := session . Start ( fmt . Sprintf ( "scp -t %s" , dir ) ) ; err != nil {
2015-06-15 14:31:17 +00:00
return err
}
2016-01-22 21:54:56 +00:00
fmt . Fprintf ( pipe , "C%#o %d %s\n" , mode , fileSize , fileName )
io . Copy ( pipe , strings . NewReader ( data ) )
fmt . Fprint ( pipe , "\x00" )
pipe . Close ( )
return session . Wait ( )
2015-06-15 14:31:17 +00:00
}