Merge pull request #1940 from nathanleclaire/gh_api_rate_limit

Add --github-api-token flag and troubleshooting section
This commit is contained in:
Nathan LeClaire 2015-10-07 13:03:59 -07:00
commit cc00ece828
4 changed files with 137 additions and 3 deletions

View File

@ -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.

View File

@ -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 {

View File

@ -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"))
}
}

11
main.go
View File

@ -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",