deduplicate excess code
This commit is contained in:
parent
54b33ad8d1
commit
fda55fe928
|
@ -8,8 +8,10 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -56,6 +58,68 @@ type TunnelDriver interface {
|
||||||
StopTunnel()
|
StopTunnel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RunTunnelCommand(cmd *exec.Cmd) error {
|
||||||
|
// set stdout and stderr so we can read what's going on.
|
||||||
|
var stdout, stderr bytes.Buffer
|
||||||
|
cmd.Stdout = &stdout
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
err := cmd.Start()
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error calling gcloud sdk to launch IAP tunnel: %s",
|
||||||
|
err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Give tunnel 30 seconds to either launch, or return an error.
|
||||||
|
// Unfortunately, the SDK doesn't provide any official acknowledgment that
|
||||||
|
// the tunnel is launched when it's not being run through a TTY so we
|
||||||
|
// are just trusting here that 30s is enough to know whether the tunnel
|
||||||
|
// launch was going to fail. Yep, feels icky to me too. But I spent an
|
||||||
|
// afternoon trying to figure out how to get the SDK to actually send
|
||||||
|
// the "Listening on port [n]" line I see when I run it manually, and I
|
||||||
|
// can't justify spending more time than that on aesthetics.
|
||||||
|
for i := 0; i < 30; i++ {
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
|
lineStderr, err := stderr.ReadString('\n')
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
log.Printf("Err from scanning stderr is %s", err)
|
||||||
|
return fmt.Errorf("Error reading stderr from tunnel launch: %s", err)
|
||||||
|
}
|
||||||
|
if lineStderr != "" {
|
||||||
|
log.Printf("stderr: %s", lineStderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
lineStdout, err := stdout.ReadString('\n')
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
log.Printf("Err from scanning stdout is %s", err)
|
||||||
|
return fmt.Errorf("Error reading stdout from tunnel launch: %s", err)
|
||||||
|
}
|
||||||
|
if lineStdout != "" {
|
||||||
|
log.Printf("stdout: %s", lineStdout)
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(lineStderr, "ERROR") {
|
||||||
|
// 4033: Either you don't have permission to access the instance,
|
||||||
|
// the instance doesn't exist, or the instance is stopped.
|
||||||
|
// The two sub-errors we may see while the permissions settle are
|
||||||
|
// "not authorized" and "failed to connect to backend," but after
|
||||||
|
// about a minute of retries this goes away and we're able to
|
||||||
|
// connect.
|
||||||
|
// 4003: "failed to connect to backend". Network blip.
|
||||||
|
if strings.Contains(lineStderr, "4033") || strings.Contains(lineStderr, "4003") {
|
||||||
|
return RetryableTunnelError{lineStderr}
|
||||||
|
} else {
|
||||||
|
log.Printf("NOT RETRYABLE: %s", lineStderr)
|
||||||
|
return fmt.Errorf("Non-retryable tunnel error: %s", lineStderr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("No error detected after tunnel launch; continuing...")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type RetryableTunnelError struct {
|
type RetryableTunnelError struct {
|
||||||
s string
|
s string
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
package googlecompute
|
package googlecompute
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/packer/helper/communicator"
|
"github.com/hashicorp/packer/helper/communicator"
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,15 +3,10 @@
|
||||||
package googlecompute
|
package googlecompute
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
"log"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewTunnelDriver() TunnelDriver {
|
func NewTunnelDriver() TunnelDriver {
|
||||||
|
@ -23,70 +18,14 @@ type TunnelDriverLinux struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TunnelDriverLinux) StartTunnel(cancelCtx context.Context, tempScriptFileName string) error {
|
func (t *TunnelDriverLinux) StartTunnel(cancelCtx context.Context, tempScriptFileName string) error {
|
||||||
// set stdout and stderr so we can read what's going on.
|
|
||||||
var stdout, stderr bytes.Buffer
|
|
||||||
|
|
||||||
cmd := exec.CommandContext(cancelCtx, tempScriptFileName)
|
cmd := exec.CommandContext(cancelCtx, tempScriptFileName)
|
||||||
cmd.Stdout = &stdout
|
|
||||||
cmd.Stderr = &stderr
|
|
||||||
|
|
||||||
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
||||||
|
|
||||||
err := cmd.Start()
|
err := RunTunnelCommand(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Error calling gcloud sdk to launch IAP tunnel: %s",
|
|
||||||
err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Give tunnel 30 seconds to either launch, or return an error.
|
|
||||||
// Unfortunately, the SDK doesn't provide any official acknowledgment that
|
|
||||||
// the tunnel is launched when it's not being run through a TTY so we
|
|
||||||
// are just trusting here that 30s is enough to know whether the tunnel
|
|
||||||
// launch was going to fail. Yep, feels icky to me too. But I spent an
|
|
||||||
// afternoon trying to figure out how to get the SDK to actually send
|
|
||||||
// the "Listening on port [n]" line I see when I run it manually, and I
|
|
||||||
// can't justify spending more time than that on aesthetics.
|
|
||||||
for i := 0; i < 30; i++ {
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
|
|
||||||
lineStderr, err := stderr.ReadString('\n')
|
|
||||||
if err != nil && err != io.EOF {
|
|
||||||
log.Printf("Err from scanning stderr is %s", err)
|
|
||||||
return fmt.Errorf("Error reading stderr from tunnel launch: %s", err)
|
|
||||||
}
|
|
||||||
if lineStderr != "" {
|
|
||||||
log.Printf("stderr: %s", lineStderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
lineStdout, err := stdout.ReadString('\n')
|
|
||||||
if err != nil && err != io.EOF {
|
|
||||||
log.Printf("Err from scanning stdout is %s", err)
|
|
||||||
return fmt.Errorf("Error reading stdout from tunnel launch: %s", err)
|
|
||||||
}
|
|
||||||
if lineStdout != "" {
|
|
||||||
log.Printf("stdout: %s", lineStdout)
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(lineStderr, "ERROR") {
|
|
||||||
// 4033: Either you don't have permission to access the instance,
|
|
||||||
// the instance doesn't exist, or the instance is stopped.
|
|
||||||
// The two sub-errors we may see while the permissions settle are
|
|
||||||
// "not authorized" and "failed to connect to backend," but after
|
|
||||||
// about a minute of retries this goes away and we're able to
|
|
||||||
// connect.
|
|
||||||
// 4003: "failed to connect to backend". Network blip.
|
|
||||||
if strings.Contains(lineStderr, "4033") || strings.Contains(lineStderr, "4003") {
|
|
||||||
return RetryableTunnelError{lineStderr}
|
|
||||||
} else {
|
|
||||||
log.Printf("NOT RETRYABLE: %s", lineStderr)
|
|
||||||
return fmt.Errorf("Non-retryable tunnel error: %s", lineStderr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("No error detected after tunnel launch; continuing...")
|
|
||||||
|
|
||||||
// Store successful command on step so we can access it to cancel it
|
// Store successful command on step so we can access it to cancel it
|
||||||
// later.
|
// later.
|
||||||
t.cmd = cmd
|
t.cmd = cmd
|
||||||
|
|
|
@ -3,18 +3,12 @@
|
||||||
package googlecompute
|
package googlecompute
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
"log"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewTunnelDriver() TunnelDriver {
|
func NewTunnelDriver() TunnelDriver {
|
||||||
log.Printf("Megan created driver for windows")
|
|
||||||
return &TunnelDriverWindows{}
|
return &TunnelDriverWindows{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,71 +17,12 @@ type TunnelDriverWindows struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TunnelDriverWindows) StartTunnel(cancelCtx context.Context, tempScriptFileName string) error {
|
func (t *TunnelDriverWindows) StartTunnel(cancelCtx context.Context, tempScriptFileName string) error {
|
||||||
log.Printf("Megan inside StartTunnel for windows")
|
|
||||||
// set stdout and stderr so we can read what's going on.
|
|
||||||
var stdout, stderr bytes.Buffer
|
|
||||||
|
|
||||||
args := []string{"/C", "call", tempScriptFileName}
|
args := []string{"/C", "call", tempScriptFileName}
|
||||||
|
|
||||||
cmd := exec.CommandContext(cancelCtx, "cmd", args...)
|
cmd := exec.CommandContext(cancelCtx, "cmd", args...)
|
||||||
cmd.Stdout = &stdout
|
err := RunTunnelCommand(cmd)
|
||||||
cmd.Stderr = &stderr
|
|
||||||
|
|
||||||
err := cmd.Start()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Megan: error calling start.")
|
|
||||||
err := fmt.Errorf("Error calling gcloud sdk to launch IAP tunnel: %s",
|
|
||||||
err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Give tunnel 30 seconds to either launch, or return an error.
|
|
||||||
// Unfortunately, the SDK doesn't provide any official acknowledgment that
|
|
||||||
// the tunnel is launched when it's not being run through a TTY so we
|
|
||||||
// are just trusting here that 30s is enough to know whether the tunnel
|
|
||||||
// launch was going to fail. Yep, feels icky to me too. But I spent an
|
|
||||||
// afternoon trying to figure out how to get the SDK to actually send
|
|
||||||
// the "Listening on port [n]" line I see when I run it manually, and I
|
|
||||||
// can't justify spending more time than that on aesthetics.
|
|
||||||
for i := 0; i < 30; i++ {
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
|
|
||||||
lineStderr, err := stderr.ReadString('\n')
|
|
||||||
if err != nil && err != io.EOF {
|
|
||||||
log.Printf("Err from scanning stderr is %s", err)
|
|
||||||
return fmt.Errorf("Error reading stderr from tunnel launch: %s", err)
|
|
||||||
}
|
|
||||||
if lineStderr != "" {
|
|
||||||
log.Printf("stderr: %s", lineStderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
lineStdout, err := stdout.ReadString('\n')
|
|
||||||
if err != nil && err != io.EOF {
|
|
||||||
log.Printf("Err from scanning stdout is %s", err)
|
|
||||||
return fmt.Errorf("Error reading stdout from tunnel launch: %s", err)
|
|
||||||
}
|
|
||||||
if lineStdout != "" {
|
|
||||||
log.Printf("stdout: %s", lineStdout)
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(lineStderr, "ERROR") {
|
|
||||||
// 4033: Either you don't have permission to access the instance,
|
|
||||||
// the instance doesn't exist, or the instance is stopped.
|
|
||||||
// The two sub-errors we may see while the permissions settle are
|
|
||||||
// "not authorized" and "failed to connect to backend," but after
|
|
||||||
// about a minute of retries this goes away and we're able to
|
|
||||||
// connect.
|
|
||||||
if strings.Contains(lineStderr, "4033") {
|
|
||||||
return RetryableTunnelError{lineStderr}
|
|
||||||
} else {
|
|
||||||
log.Printf("NOT RETRYABLE: %s", lineStderr)
|
|
||||||
return fmt.Errorf("Non-retryable tunnel error: %s", lineStderr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("No error detected after tunnel launch; continuing...")
|
|
||||||
|
|
||||||
// Store successful command on step so we can access it to cancel it
|
// Store successful command on step so we can access it to cancel it
|
||||||
// later.
|
// later.
|
||||||
t.cmd = cmd
|
t.cmd = cmd
|
||||||
|
|
Loading…
Reference in New Issue