github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/environs/manual/fakessh_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package manual_test
     5  
     6  import (
     7  	"fmt"
     8  	"io/ioutil"
     9  	"path/filepath"
    10  	"strings"
    11  
    12  	"github.com/juju/testing"
    13  	jc "github.com/juju/testing/checkers"
    14  	gc "gopkg.in/check.v1"
    15  
    16  	"github.com/juju/juju/environs/manual"
    17  )
    18  
    19  // sshscript should only print the result on the first execution,
    20  // to handle the case where it's called multiple times. On
    21  // subsequent executions, it should find the next 'ssh' in $PATH
    22  // and exec that.
    23  var sshscript = `#!/bin/bash --norc
    24  if [ ! -e "$0.run" ]; then
    25      touch "$0.run"
    26      if [ -e "$0.expected-input" ]; then
    27          diff "$0.expected-input" -
    28          exitcode=$?
    29          if [ $exitcode -ne 0 ]; then
    30              echo "ERROR: did not match expected input" >&2
    31              exit $exitcode
    32          fi
    33          else
    34              head >/dev/null
    35          fi
    36      # stdout
    37      %s
    38      # stderr
    39      %s
    40      exit %d
    41  else
    42      export PATH=${PATH#*:}
    43      exec ssh $*
    44  fi`
    45  
    46  // installFakeSSH creates a fake "ssh" command in a new $PATH,
    47  // updates $PATH, and returns a function to reset $PATH to its
    48  // original value when called.
    49  //
    50  // input may be:
    51  //    - nil (ignore input)
    52  //    - a string (match input exactly)
    53  // output may be:
    54  //    - nil (no output)
    55  //    - a string (stdout)
    56  //    - a slice of strings, of length two (stdout, stderr)
    57  func installFakeSSH(c *gc.C, input, output interface{}, rc int) testing.Restorer {
    58  	fakebin := c.MkDir()
    59  	ssh := filepath.Join(fakebin, "ssh")
    60  	switch input := input.(type) {
    61  	case nil:
    62  	case string:
    63  		sshexpectedinput := ssh + ".expected-input"
    64  		err := ioutil.WriteFile(sshexpectedinput, []byte(input), 0644)
    65  		c.Assert(err, jc.ErrorIsNil)
    66  	default:
    67  		c.Errorf("input has invalid type: %T", input)
    68  	}
    69  	var stdout, stderr string
    70  	switch output := output.(type) {
    71  	case nil:
    72  	case string:
    73  		stdout = fmt.Sprintf("cat<<EOF\n%s\nEOF", output)
    74  	case []string:
    75  		c.Assert(output, gc.HasLen, 2)
    76  		stdout = fmt.Sprintf("cat<<EOF\n%s\nEOF", output[0])
    77  		stderr = fmt.Sprintf("cat>&2<<EOF\n%s\nEOF", output[1])
    78  	}
    79  	script := fmt.Sprintf(sshscript, stdout, stderr, rc)
    80  	err := ioutil.WriteFile(ssh, []byte(script), 0777)
    81  	c.Assert(err, jc.ErrorIsNil)
    82  	return testing.PatchEnvPathPrepend(fakebin)
    83  }
    84  
    85  // installDetectionFakeSSH installs a fake SSH command, which will respond
    86  // to the series/hardware detection script with the specified
    87  // series/arch.
    88  func installDetectionFakeSSH(c *gc.C, series, arch string) testing.Restorer {
    89  	if series == "" {
    90  		series = "precise"
    91  	}
    92  	if arch == "" {
    93  		arch = "amd64"
    94  	}
    95  	detectionoutput := strings.Join([]string{
    96  		series,
    97  		arch,
    98  		"MemTotal: 4096 kB",
    99  		"processor: 0",
   100  	}, "\n")
   101  	return installFakeSSH(c, manual.DetectionScript, detectionoutput, 0)
   102  }
   103  
   104  // fakeSSH wraps the invocation of InstallFakeSSH based on the parameters.
   105  type fakeSSH struct {
   106  	Series string
   107  	Arch   string
   108  
   109  	// Provisioned should be set to true if the fakeSSH script
   110  	// should respond to checkProvisioned with a non-empty result.
   111  	Provisioned bool
   112  
   113  	// exit code for the checkProvisioned script.
   114  	CheckProvisionedExitCode int
   115  
   116  	// exit code for the machine agent provisioning script.
   117  	ProvisionAgentExitCode int
   118  
   119  	// InitUbuntuUser should be set to true if the fakeSSH script
   120  	// should respond to an attempt to initialise the ubuntu user.
   121  	InitUbuntuUser bool
   122  
   123  	// there are conditions other than error in the above
   124  	// that might cause provisioning to not go ahead, such
   125  	// as tools being missing.
   126  	SkipProvisionAgent bool
   127  
   128  	// detection will be skipped if the series/hardware were
   129  	// detected ahead of time. This should always be set to
   130  	// true when testing Bootstrap.
   131  	SkipDetection bool
   132  }
   133  
   134  // install installs fake SSH commands, which will respond to
   135  // manual provisioning/bootstrapping commands with the specified
   136  // output and exit codes.
   137  func (r fakeSSH) install(c *gc.C) testing.Restorer {
   138  	var restore testing.Restorer
   139  	add := func(input, output interface{}, rc int) {
   140  		restore = restore.Add(installFakeSSH(c, input, output, rc))
   141  	}
   142  	if !r.SkipProvisionAgent {
   143  		add(nil, nil, r.ProvisionAgentExitCode)
   144  	}
   145  	if !r.SkipDetection {
   146  		restore.Add(installDetectionFakeSSH(c, r.Series, r.Arch))
   147  	}
   148  	var checkProvisionedOutput interface{}
   149  	if r.Provisioned {
   150  		checkProvisionedOutput = "/etc/init/jujud-machine-0.conf"
   151  	}
   152  	add(manual.CheckProvisionedScript, checkProvisionedOutput, r.CheckProvisionedExitCode)
   153  	if r.InitUbuntuUser {
   154  		add("", nil, 0)
   155  	}
   156  	return restore
   157  }