From a5b0ebe0ecb9fef5999a741a527afa9140cbb304 Mon Sep 17 00:00:00 2001 From: Nathan LeClaire Date: Tue, 6 Oct 2015 15:12:18 -0700 Subject: [PATCH] Add --github-api-token flag and troubleshooting section Signed-off-by: Nathan LeClaire --- README.md | 72 +++++++++++++++++++++++++++++++++ libmachine/mcnutils/b2d.go | 29 ++++++++++++- libmachine/mcnutils/b2d_test.go | 28 +++++++++++++ main.go | 11 ++++- 4 files changed, 137 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e7b73824eb..7d6cc6b3a9 100644 --- a/README.md +++ b/README.md @@ -54,3 +54,75 @@ Full documentation [is available here](https://docs.docker.com/machine/). Want to hack on Machine? Please start with the [Contributing Guide](https://github.com/docker/machine/blob/master/CONTRIBUTING.md). +## Troubleshooting + +Docker Machine tries to do the right thing in a variety of scenarios but +sometimes things do not go according to plan. Here is a quick troubleshooting +guide which may help you to resolve of the issues you may be seeing. + +Note that some of the suggested solutions are only available on the Docker +Machine master branch. If you need them, consider compiling Docker Machine from +source. There are also [unofficial pre-compiled master +binaries](https://docker-machine-builds.evanhazlett.com/latest) hosted by +[@ehazlett](https://github.com/ehazlett). + +#### `docker-machine` hangs + +A common issue with Docker Machine is that it will hang when attempting to start +up the virtual machine. Since starting the machine is part of the `create` +process, `create` is often where these types of errors show up. + +A hang could be due to a variety of factors, but the most common suspect is +networking. Consider the following: + +- Are you using a VPN? If so, try disconnecting and see if creation will + succeed without the VPN. Some VPN software aggressively controls routes and + you may need to [manually add the route](https://github.com/docker/machine/issues/1500#issuecomment-121134958). +- Are you connected to a proxy server, corporate or otherwise? If so, take a + look at the `--no-proxy` flag for `env` and at [setting environment variables + for the created Docker Engine](https://docs.docker.com/machine/reference/create/#specifying-configuration-options-for-the-created-docker-engine). +- Are there a lot of host-only interfaces listed by the command `VBoxManage list + hostonlyifs`? If so, this has sometimes been known to cause bugs. Consider + removing the ones you are not using (`VBoxManage hostonlyif remove name`) and + trying machine creation again. + +We are keenly aware of this as an issue and working towards a set of solutions +which is robust for all users, so please give us feedback and/or report issues, +workarounds, and desired workflows as you discover them. + +#### Machine creation errors out before finishing + +If you see messages such as "exit status 1" creating machines with VirtualBox, +this frequently indicates that there is an issue with VirtualBox itself. Please +[file an issue](https://github.com/docker/machine/issues/new) and include a link +to a [Github Gist](https://gist.github.com/) with the output of the VirtualBox +log (usually located at +`$HOME/.docker/machine/machines/machinename/machinename/Logs/VBox.log`), as well +as the output of running the Docker Machine command which is failing with the +global `--debug` flag enabled. This will help us to track down which versions +of VirtualBox are failing where, and under which conditions. + +If you see messages such as "exit status 255", this frequently indicates there +has been an issue with SSH. Please investigate your SSH configuration if you +have one, and/or [file an issue](https://github.com/docker/machine/issues). + +#### "You may be getting rate limited by Github" error message + +In order to `create` or `upgrade` virtual machines running Docker, Docker +Machine will check the Github API for the latest release of the [boot2docker +operating system](https://github.com/boot2docker/boot2docker). The Github API +allows for a small number of unauthenticated requests from a given client, but +if you share an IP address with many other users (e.g. in an office), you may +get rate limited by their API, and Docker Machine will error out with messages +indicating this. + +In order to work around this issue, you can [generate a +token](https://help.github.com/articles/creating-an-access-token-for-command-line-use/) +and pass it to Docker Machine using the global `--github-api-token` flag like +so: + +```console +$ docker-machine --github-api-token=token create -d virtualbox newbox +``` + +This should eliminate any issues you've been experiencing with rate limiting. diff --git a/libmachine/mcnutils/b2d.go b/libmachine/mcnutils/b2d.go index d781078767..148c83eafc 100644 --- a/libmachine/mcnutils/b2d.go +++ b/libmachine/mcnutils/b2d.go @@ -15,6 +15,10 @@ import ( "github.com/docker/machine/libmachine/log" ) +var ( + GithubApiToken string +) + const ( timeout = time.Second * 5 ) @@ -70,15 +74,36 @@ func NewB2dUtils(githubApiBaseUrl, githubBaseUrl, storePath string) *B2dUtils { } } +func (b *B2dUtils) getReleasesRequest() (*http.Request, error) { + apiUrl := fmt.Sprintf("%s/repos/boot2docker/boot2docker/releases", b.githubApiBaseUrl) + + req, err := http.NewRequest("GET", apiUrl, nil) + if err != nil { + return nil, err + } + + if GithubApiToken != "" { + req.Header.Add("Authorization", fmt.Sprintf("token %s", GithubApiToken)) + } + + return req, nil +} + // Get the latest boot2docker release tag name (e.g. "v0.6.0"). // FIXME: find or create some other way to get the "latest release" of boot2docker since the GitHub API has a pretty low rate limit on API requests func (b *B2dUtils) GetLatestBoot2DockerReleaseURL() (string, error) { client := getClient() - apiUrl := fmt.Sprintf("%s/repos/boot2docker/boot2docker/releases", b.githubApiBaseUrl) - rsp, err := client.Get(apiUrl) + + req, err := b.getReleasesRequest() if err != nil { return "", err } + + rsp, err := client.Do(req) + if err != nil { + return "", err + } + defer rsp.Body.Close() var t []struct { diff --git a/libmachine/mcnutils/b2d_test.go b/libmachine/mcnutils/b2d_test.go index 0e49deeb02..78f01c0b26 100644 --- a/libmachine/mcnutils/b2d_test.go +++ b/libmachine/mcnutils/b2d_test.go @@ -56,3 +56,31 @@ func TestDownloadIso(t *testing.T) { t.Fatalf("expected data \"%s\"; received \"%s\"", testData, string(data)) } } + +func TestGetReleasesRequestNoToken(t *testing.T) { + GithubApiToken = "" + b2d := NewB2dUtils("", "", "/tmp/store") + req, err := b2d.getReleasesRequest() + if err != nil { + t.Fatal("Expected err to be nil, got ", err) + } + + if req.Header.Get("Authorization") != "" { + t.Fatal("Expected not to get an 'Authorization' header, but got one: ", req.Header.Get("Authorization")) + } +} + +func TestGetReleasesRequest(t *testing.T) { + expectedToken := "CATBUG" + GithubApiToken = expectedToken + b2d := NewB2dUtils("", "", "/tmp/store") + + req, err := b2d.getReleasesRequest() + if err != nil { + t.Fatal("Expected err to be nil, got ", err) + } + + if req.Header.Get("Authorization") != fmt.Sprintf("token %s", expectedToken) { + t.Fatal("Header was not set as expected: ", req.Header.Get("Authorization")) + } +} diff --git a/main.go b/main.go index dfff262e9a..fa3f123801 100644 --- a/main.go +++ b/main.go @@ -7,10 +7,10 @@ import ( "strconv" "github.com/codegangsta/cli" - "github.com/docker/machine/commands" "github.com/docker/machine/commands/mcndirs" "github.com/docker/machine/libmachine/log" + "github.com/docker/machine/libmachine/mcnutils" "github.com/docker/machine/libmachine/ssh" "github.com/docker/machine/version" ) @@ -75,9 +75,12 @@ func main() { app.Author = "Docker Machine Contributors" app.Email = "https://github.com/docker/machine" app.Before = func(c *cli.Context) error { + // TODO: Need better handling of config, everything is too + // complected together right now. if c.GlobalBool("native-ssh") { ssh.SetDefaultClient(ssh.Native) } + mcnutils.GithubApiToken = c.GlobalString("github-api-token") return nil } app.Commands = commands.Commands @@ -120,6 +123,12 @@ func main() { Usage: "Private key used in client TLS auth", Value: "", }, + cli.StringFlag{ + EnvVar: "MACHINE_GITHUB_API_TOKEN", + Name: "github-api-token", + Usage: "Token to use for requests to the Github API", + Value: "", + }, cli.BoolFlag{ EnvVar: "MACHINE_NATIVE_SSH", Name: "native-ssh",