Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use custom ngrok config so we can specify api url. #93

Merged
merged 1 commit into from
Mar 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 23 additions & 9 deletions bootstrap/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package bootstrap
import (
"context"
"fmt"
"net"
"io/ioutil"
"os"
"os/exec"
"os/signal"
Expand Down Expand Up @@ -129,16 +129,30 @@ Follow these instructions to create a token (we don't store any tokens):
// Create ngrok tunnel.
colorstring.Println("[white]=> creating secure tunnel")
s.Start()
// Check if there is already an ngrok running by seeing if there's already
// something bound to its API port.
conn, err := net.Dial("tcp", ngrokAPIURL)
// We expect an error.
if err == nil {
conn.Close() // nolint: errcheck
return errors.New("unable to start ngrok because there is already something bound to its API port: " + ngrokAPIURL)

// We use a config file so we can set ngrok's API port (web_addr). We use
// the API to get the public URL and if there's already ngrok running, it
// will just choose a random API port and we won't be able to get the right
// url.
ngrokConfig := fmt.Sprintf(`
web_addr: %s
tunnels:
atlantis:
addr: %d
bind_tls: true
proto: http
`, ngrokAPIURL, atlantisPort)

ngrokConfigFile, err := ioutil.TempFile("", "")
if err != nil {
return errors.Wrap(err, "creating ngrok config file")
}
err = ioutil.WriteFile(ngrokConfigFile.Name(), []byte(ngrokConfig), 0600)
if err != nil {
return errors.Wrap(err, "writing ngrok config file")
}

ngrokCmd, err := executeCmd("/tmp/ngrok", []string{"http", "4141"})
ngrokCmd, err := executeCmd("/tmp/ngrok", []string{"start", "atlantis", "--config", ngrokConfigFile.Name()})
if err != nil {
return errors.Wrapf(err, "creating ngrok tunnel")
}
Expand Down
43 changes: 24 additions & 19 deletions bootstrap/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ import (
"path/filepath"
"syscall"

"github.com/pkg/errors"
"golang.org/x/crypto/ssh/terminal"
)

var hashicorpReleasesURL = "https://releases.hashicorp.com"
var terraformVersion = "0.10.8"
var ngrokDownloadURL = "https://bin.equinox.io/c/4VmDzA7iaHb"
var ngrokAPIURL = "localhost:4040"
const hashicorpReleasesURL = "https://releases.hashicorp.com"
const terraformVersion = "0.10.8"
const ngrokDownloadURL = "https://bin.equinox.io/c/4VmDzA7iaHb"
const ngrokAPIURL = "localhost:41414" // We hope this isn't used.
const atlantisPort = 4141

func readPassword() (string, error) {
password, err := terminal.ReadPassword(syscall.Stdin)
Expand Down Expand Up @@ -90,35 +92,38 @@ func unzip(archive, target string) error {
}

func getTunnelAddr() (string, error) {
response, err := http.Get(fmt.Sprintf("http://%s/api/tunnels", ngrokAPIURL))
tunAPI := fmt.Sprintf("http://%s/api/tunnels", ngrokAPIURL)
response, err := http.Get(tunAPI)
if err != nil {
return "", err
}
defer response.Body.Close() // nolint: errcheck

type tunnel struct {
Name string `json:"name"`
URI string `json:"uri"`
PublicURL string `json:"public_url"`
Proto string `json:"http"`
}

type tunnels struct {
Tunnels []tunnel
Tunnels []struct {
PublicURL string `json:"public_url"`
Proto string `json:"proto"`
Config struct {
Addr string `json:"addr"`
} `json:"config"`
} `json:"tunnels"`
}

var t tunnels

err = json.NewDecoder(response.Body).Decode(&t)
if err != nil {
return "", err
if err = json.NewDecoder(response.Body).Decode(&t); err != nil {
return "", errors.Wrapf(err, "parsing ngrok api at %s", tunAPI)
}

if len(t.Tunnels) != 2 {
return "", fmt.Errorf("didn't find tunnels that were expected to be created")
// Find the tunnel we just created.
expAtlantisURL := fmt.Sprintf("localhost:%d", atlantisPort)
for _, tun := range t.Tunnels {
if tun.Proto == "https" && tun.Config.Addr == expAtlantisURL {
return tun.PublicURL, nil
}
}

return t.Tunnels[1].PublicURL, nil
return "", fmt.Errorf("did not find ngrok tunnel with proto 'https' and config.addr '%s' in list of tunnels at %s", expAtlantisURL, tunAPI)
}

// nolint: unparam
Expand Down