github.com/arunkumar7540/cli@v6.45.0+incompatible/integration/v7/isolated/ssh_command_test.go (about) 1 package isolated 2 3 import ( 4 "fmt" 5 "net/http" 6 "time" 7 8 "code.cloudfoundry.org/cli/integration/helpers" 9 . "github.com/onsi/ginkgo" 10 . "github.com/onsi/gomega" 11 . "github.com/onsi/gomega/gbytes" 12 . "github.com/onsi/gomega/gexec" 13 ) 14 15 var _ = Describe("ssh command", func() { 16 var ( 17 appName string 18 orgName string 19 spaceName string 20 ) 21 22 BeforeEach(func() { 23 appName = helpers.PrefixedRandomName("app") 24 orgName = helpers.NewOrgName() 25 spaceName = helpers.NewSpaceName() 26 }) 27 28 When("--help flag is set", func() { 29 It("Displays command usage to output", func() { 30 session := helpers.CF("ssh", "--help") 31 32 Eventually(session).Should(Say(`NAME:`)) 33 Eventually(session).Should(Say(`ssh - SSH to an application container instance`)) 34 Eventually(session).Should(Say(`USAGE:`)) 35 Eventually(session).Should(Say(`cf ssh APP_NAME \[--process PROCESS\] \[-i INDEX\] \[-c COMMAND\]...\n`)) 36 Eventually(session).Should(Say(`\[-L \[BIND_ADDRESS:\]LOCAL_PORT:REMOTE_HOST:REMOTE_PORT\]\.\.\. \[--skip-remote-execution\]`)) 37 Eventually(session).Should(Say(`\[--disable-pseudo-tty \| --force-pseudo-tty \| --request-pseudo-tty\] \[--skip-host-validation\]`)) 38 Eventually(session).Should(Say(`OPTIONS:`)) 39 Eventually(session).Should(Say(`--app-instance-index, -i\s+App process instance index \(Default: 0\)`)) 40 Eventually(session).Should(Say(`--command, -c\s+Command to run`)) 41 Eventually(session).Should(Say(`--disable-pseudo-tty, -T\s+Disable pseudo-tty allocation`)) 42 Eventually(session).Should(Say(`--force-pseudo-tty\s+Force pseudo-tty allocation`)) 43 Eventually(session).Should(Say(`-L\s+Local port forward specification`)) 44 Eventually(session).Should(Say(`--process\s+App process name \(Default: web\)`)) 45 Eventually(session).Should(Say(`--request-pseudo-tty, -t\s+Request pseudo-tty allocation`)) 46 Eventually(session).Should(Say(`--skip-host-validation, -k\s+Skip host key validation\. Not recommended!`)) 47 Eventually(session).Should(Say(`--skip-remote-execution, -N\s+Do not execute a remote command`)) 48 Eventually(session).Should(Say(`ENVIRONMENT:`)) 49 Eventually(session).Should(Say(`all_proxy=\s+Specify a proxy server to enable proxying for all requests`)) 50 Eventually(session).Should(Say(`SEE ALSO:`)) 51 Eventually(session).Should(Say(`allow-space-ssh, enable-ssh, space-ssh-allowed, ssh-code, ssh-enabled`)) 52 Eventually(session).Should(Exit(0)) 53 }) 54 }) 55 56 When("the app name is not provided", func() { 57 It("tells the user that the app name is required, prints help text, and exits 1", func() { 58 session := helpers.CF("ssh") 59 60 Eventually(session.Err).Should(Say("Incorrect Usage: the required argument `APP_NAME` was not provided")) 61 Eventually(session).Should(Say("NAME:")) 62 Eventually(session).Should(Exit(1)) 63 }) 64 }) 65 66 When("the environment is not setup correctly", func() { 67 It("fails with the appropriate errors", func() { 68 helpers.CheckEnvironmentTargetedCorrectly(true, true, ReadOnlyOrg, "ssh", appName) 69 }) 70 }) 71 72 When("the environment is setup correctly", func() { 73 BeforeEach(func() { 74 helpers.SetupCF(orgName, spaceName) 75 }) 76 77 AfterEach(func() { 78 helpers.QuickDeleteOrg(orgName) 79 }) 80 81 When("the app does not exist", func() { 82 It("it displays the app does not exist", func() { 83 session := helpers.CF("ssh", appName) 84 Eventually(session).Should(Say("FAILED")) 85 Eventually(session.Err).Should(Say("App '%s' not found", appName)) 86 Eventually(session).Should(Exit(1)) 87 }) 88 }) 89 90 When("the app exists", func() { 91 BeforeEach(func() { 92 helpers.WithProcfileApp(func(appDir string) { 93 Eventually(helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "push", appName)).Should(Exit(0)) 94 }) 95 }) 96 97 Context("TTY Options", func() { 98 // * The columns specify the various TTY flags passed to cf ssh 99 // (--disable-pseudo-tty, --force-pseudo-tty, --request-pseudo-tty). 100 // * The rows specify what kind of shell you’re running "cf ssh" from. To 101 // simulate an interactive shell, simply use your terminal as always. 102 // To simulate a non-interactive shell, append "<< EOF <new-line> 103 // <command-to-execute-on-remote-host> <new-line> EOF" to your command 104 // * The values (yes/no) determine whether a TTY session should be 105 // allocated on the remote host. Verify by running "TTY" on remote host. 106 // 107 // TTY Option -> | Default(auto) | Disable | Force | Request 108 // Shell_Type__________________|_______________|_________|_______|_____________ 109 // interactive | Yes | No | Yes | Yes 110 // non-interactive | No | No | No | No 111 // interactive w/ commands | No | No | Yes | Yes 112 // non-interactive w/ commands | No | No | Yes | No 113 114 When("the running session is interactive", func() { 115 // This should be tested manually (launching an interactive shell in code is hard) 116 }) 117 118 When("the running session is non-interactive", func() { 119 When("providing commands to run on the remote host", func() { 120 When("using default tty option (auto)", func() { 121 It("the remote shell is not TTY", func() { 122 // we echo hello because a successful ssh call returns the status 123 session := helpers.CF("ssh", appName, "-c tty;", "-c echo hello") 124 Eventually(session).Should(Say("not a tty")) 125 Eventually(session).Should(Exit(0)) 126 }) 127 }) 128 129 When("disable-pseudo-tty is specified", func() { 130 It("the remote shell is not TTY", func() { 131 session := helpers.CF("ssh", appName, "--disable-pseudo-tty", "-c tty;", "-c echo hello") 132 Eventually(session).Should(Say("not a tty")) 133 Eventually(session).Should(Exit(0)) 134 }) 135 }) 136 137 When("force-pseudo-tty is specified", func() { 138 It("the remote shell is TTY", func() { 139 session := helpers.CF("ssh", appName, "--force-pseudo-tty", "-c tty;", "-c echo hello") 140 Eventually(session).ShouldNot(Say("not a tty")) 141 Eventually(session).Should(Say("/dev/*")) 142 Eventually(session).Should(Exit(0)) 143 }) 144 }) 145 146 When("request-pseudo-tty is specified", func() { 147 It("the remote shell is not TTY", func() { 148 session := helpers.CF("ssh", appName, "--request-pseudo-tty", "-c tty;", "-c echo hello") 149 Eventually(session).Should(Say("not a tty")) 150 Eventually(session).Should(Exit(0)) 151 }) 152 }) 153 }) 154 155 When("not providing commands as args", func() { 156 var buffer *Buffer 157 158 BeforeEach(func() { 159 buffer = NewBuffer() 160 }) 161 162 When("using default tty option (auto)", func() { 163 It("the remote shell is not TTY", func() { 164 _, err := buffer.Write([]byte("tty\n")) 165 Expect(err).ToNot(HaveOccurred()) 166 _, err = buffer.Write([]byte("echo hello\n")) 167 Expect(err).ToNot(HaveOccurred()) 168 _, err = buffer.Write([]byte("exit\n")) 169 Expect(err).ToNot(HaveOccurred()) 170 session := helpers.CFWithStdin(buffer, "ssh", appName) 171 Eventually(session).Should(Say("not a tty")) 172 Eventually(session).Should(Exit(0)) 173 }) 174 }) 175 176 When("disable-pseudo-tty is specified", func() { 177 It("the remote shell is not TTY", func() { 178 _, err := buffer.Write([]byte("tty\n")) 179 Expect(err).ToNot(HaveOccurred()) 180 181 _, err = buffer.Write([]byte("echo hello\n")) 182 Expect(err).ToNot(HaveOccurred()) 183 184 _, err = buffer.Write([]byte("exit\n")) 185 Expect(err).ToNot(HaveOccurred()) 186 187 session := helpers.CFWithStdin(buffer, "ssh", appName, "--disable-pseudo-tty") 188 Eventually(session).Should(Say("not a tty")) 189 Eventually(session).Should(Exit(0)) 190 }) 191 }) 192 193 When("force-pseudo-tty is specified", func() { 194 It("the remote shell is TTY", func() { 195 _, err := buffer.Write([]byte("tty\n")) 196 Expect(err).ToNot(HaveOccurred()) 197 198 _, err = buffer.Write([]byte("echo hello\n")) 199 Expect(err).ToNot(HaveOccurred()) 200 201 _, err = buffer.Write([]byte("exit\n")) 202 Expect(err).ToNot(HaveOccurred()) 203 session := helpers.CFWithStdin(buffer, "ssh", appName, "--force-pseudo-tty") 204 205 Eventually(session).ShouldNot(Say("not a tty")) 206 Eventually(session).Should(Say("/dev/*")) 207 Eventually(session).Should(Exit(0)) 208 }) 209 }) 210 211 When("request-pseudo-tty is specified", func() { 212 It("the remote shell is TTY", func() { 213 _, err := buffer.Write([]byte("tty\n")) 214 Expect(err).ToNot(HaveOccurred()) 215 216 _, err = buffer.Write([]byte("echo hello\n")) 217 Expect(err).ToNot(HaveOccurred()) 218 219 _, err = buffer.Write([]byte("exit\n")) 220 Expect(err).ToNot(HaveOccurred()) 221 222 session := helpers.CFWithStdin(buffer, "ssh", appName, "--request-pseudo-tty") 223 Eventually(session).Should(Say("not a tty")) 224 Eventually(session).Should(Exit(0)) 225 }) 226 }) 227 }) 228 }) 229 }) 230 231 It("ssh's to the process 'web', index '0'", func() { 232 session := helpers.CF("ssh", appName, "-c", "ps aux;", "-c", "env") 233 // To verify we ssh'd into the web process we examine processes 234 // that were launched that are unique to that process 235 Eventually(session).Should(Say("vcap.*ruby")) 236 Eventually(session).Should(Say("INSTANCE_INDEX=0")) 237 Eventually(session).Should(Exit(0)) 238 }) 239 240 When("commands to run are specified", func() { 241 It("ssh's to the default container and runs the commands", func() { 242 session := helpers.CF("ssh", appName, "-c", "ls;", "-c", "echo $USER") 243 Eventually(session).Should(Say("app")) 244 Eventually(session).Should(Say("deps")) 245 Eventually(session).Should(Say("logs")) 246 Eventually(session).Should(Say("vcap")) 247 Eventually(session).Should(Exit(0)) 248 }) 249 }) 250 251 When("the application hasn't started", func() { 252 BeforeEach(func() { 253 session := helpers.CF("v3-stop", appName) 254 Eventually(session).Should(Exit(0)) 255 }) 256 257 It("prints an error message", func() { 258 session := helpers.CF("ssh", appName) 259 Eventually(session).Should(Say("FAILED")) 260 Eventually(session.Err).Should(Say(fmt.Sprintf("Application '%s' is not in the STARTED state", appName))) 261 Eventually(session).Should(Exit(1)) 262 }) 263 }) 264 265 When("the remote command exits with a different status code", func() { 266 It("exits with that status code", func() { 267 session := helpers.CF("ssh", appName, "-c", "asdf") 268 Eventually(session).Should(Exit(127)) 269 }) 270 }) 271 272 When("port forwarding is used", func() { 273 var port int 274 275 BeforeEach(func() { 276 port = 55500 + GinkgoParallelNode() 277 }) 278 279 It("configures local port to connect to the app port", func() { 280 session := helpers.CF("ssh", appName, "-N", "-L", fmt.Sprintf("%d:localhost:8080", port)) 281 282 time.Sleep(35 * time.Second) // Need to wait a few seconds for pipes to connect. 283 response, err := http.Get(fmt.Sprintf("http://localhost:%d/", port)) 284 Expect(err).ToNot(HaveOccurred()) 285 defer response.Body.Close() 286 287 Eventually(BufferReader(response.Body)).Should(Say("WEBrick")) 288 289 session.Kill() 290 Eventually(session).Should(Exit()) 291 }) 292 }) 293 294 When("a process is specified", func() { 295 When("the process does not exist", func() { 296 It("displays the process does not exist", func() { 297 session := helpers.CF("ssh", appName, "--process", "fake-process") 298 Eventually(session).Should(Say("FAILED")) 299 Eventually(session.Err).Should(Say("Process fake-process not found")) 300 Eventually(session).Should(Exit(1)) 301 }) 302 }) 303 304 When("the process exists", func() { 305 BeforeEach(func() { 306 Eventually(helpers.CF("scale", appName, "--process", "console", "-i", "1")).Should(Exit(0)) 307 }) 308 309 It("ssh's to the process's default index", func() { 310 session := helpers.CF("ssh", appName, "--process", "console", "-c", "ps aux;", "-c", "env") 311 Eventually(session).Should(Say("vcap.*irb")) 312 Eventually(session).Should(Say("INSTANCE_INDEX=0")) 313 Eventually(session).Should(Exit(0)) 314 }) 315 316 When("the index is specified", func() { 317 When("the index does not exist", func() { 318 It("returns an instance not found error", func() { 319 session := helpers.CF("ssh", appName, "--process", "console", "-i", "1", "-c", "ps aux;", "-c", "env") 320 Eventually(session).Should(Say("FAILED")) 321 Eventually(session.Err).Should(Say("Instance %d of process console not found", 1)) 322 Eventually(session).Should(Exit(1)) 323 }) 324 }) 325 326 When("the index exists", func() { 327 It("ssh's to the provided index", func() { 328 session := helpers.CF("ssh", appName, "--process", "console", "-i", "0", "-c", "ps aux;", "-c", "env") 329 Eventually(session).Should(Say("vcap.*irb")) 330 Eventually(session).Should(Say("INSTANCE_INDEX=0")) 331 Eventually(session).Should(Exit(0)) 332 }) 333 }) 334 }) 335 }) 336 }) 337 338 When("a user isn't authorized", func() { 339 var ( 340 newUser string 341 newPass string 342 ) 343 344 BeforeEach(func() { 345 newUser = helpers.NewUsername() 346 newPass = helpers.NewPassword() 347 348 Eventually(helpers.CF("create-user", newUser, newPass)).Should(Exit(0)) 349 Eventually(helpers.CF("set-space-role", newUser, orgName, spaceName, "SpaceAuditor")).Should(Exit(0)) 350 env := map[string]string{ 351 "CF_USERNAME": newUser, 352 "CF_PASSWORD": newPass, 353 } 354 Eventually(helpers.CFWithEnv(env, "auth")).Should(Exit(0)) 355 helpers.TargetOrgAndSpace(orgName, spaceName) 356 }) 357 358 AfterEach(func() { 359 helpers.LoginCF() 360 }) 361 362 It("returns an error", func() { 363 session := helpers.CF("ssh", appName) 364 365 Eventually(session.Err).Should(Say("Error opening SSH connection: You are not authorized to perform the requested action.")) 366 Eventually(session).Should(Exit(1)) 367 }) 368 }) 369 }) 370 }) 371 })