Machine: eval $(docker-machine env foo) does not exit 1 in case of failure

Created on 5 Feb 2016  路  6Comments  路  Source: docker/machine

Usually, docker-machine env foobar returns this:

export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://127.0.0.1:2376"
export DOCKER_CERT_PATH="/over/the/rainbow/.docker/machine/machines/foobar"
export DOCKER_MACHINE_NAME="foobar"
# Run this command to configure your shell: 
# eval $(docker-machine env foobar)

Following the advice to eval the command substitution, I learned today that this script will always exit 0, even if it hits an error (in my case it was ErrCertInvalid). Additionally, it doesn't tell you that the previously active machine is _still active_, which is super bad.

This becomes a problem when you run something like this:

eval $(docker-machine env foobar) && docker volume rm -f $(docker volume ls -q)

Because instead of running that command on foobar, you end up nuking the machine your previously active machine. Personally, I just spent a bunch of time starting containers on the wrong machine and being confused, like this:

$ cd foobar/
$ eval $(docker-machine env foobar)
Error checking TLS connection: Error checking and/or regenerating the certs: There was an error validating certificates for host "127.0.0.1:2376": x509: certi
ficate is valid for 1.2.3.4.5, not 127.0.0.1
You can attempt to regenerate them using 'docker-machine regenerate-certs [name]'.
Be advised that this will trigger a Docker daemon restart which will stop running containers.

$ docker-machine regenerate-certs foobar
Regenerate TLS machine certs?  Warning: this is irreversible. (y/n): y
Regenerating TLS certificates
Detecting the provisioner...
Installing Docker...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
$ docker-compose up -d
Starting foobar_db_1
Starting foobar_wsgi_1
Starting foobar_web_1
Recreating foobar_dev_1
$ curl -m 10 $(docker-machine ip foobar)
curl: (28) Connection timed out after 10001 milliseconds

*lots of investigation and swear words*

$ docker-machine active
not-foobar

I think the minimum viable fix here would be to alert the user when their machine hasn't been activated. Ideally eval $(docker-machine env foobar) wouldn't exit 0 when there are errors, but returning an exit code at the beginning/end of the error might not be the most aesthetically pleasing. I'd be happy to put a PR together if we can decide on the best way to deal with this.

Cheers!

arecli kinenhancement

Most helpful comment

@MichaelSp here is mine

eval $(docker-machine env $MACHINE_NAME || echo "exit $?")

All 6 comments

I'm not sure that there's anything we can do about the exit status of eval -- it seems to always succeed if the passed argument is a subshell, e.g.:

$ eval $(exit 1)
$ echo $?
0

Running eval $(docker-machine env) will still spit out errors printed to STDERR, so I'm not sure what else we can do. Any suggestions?

I usually manually verify that the DOCKER_HOST I'm running against is the intended one in the case of destructive operations. This is for similar reasons as checking that anything which involves some variation of rm -rf foo/bar/* expands to what you expect it to.

I faced a similar problem today with docker-machine env --shell cmd default when it said that there was an error with the TLS certificate and I executed docker-machine regenerate-certs default to create new ones which messed up everything.

https://github.com/docker/machine/issues/3023 is related

@nathanleclaire
You're right, exit statuses aren't the way to go, although sending a warning to STDERR and false to STDOUT would do the trick. I think there are three possible solutions:

  1. The user should be advised that the machine has _not_ been activated.
  2. All Docker Machine environment variables should be unset.
  3. The eval command should return an exit status of 1.
docker-machine-env-fixed () {
  eval $(docker-machine env "$1")
  if [ "$(docker-machine active)" !+ "$1" ]; then
    >&2 echo "Machine \"$1\" has NOT been activated."
    eval "$(docker-machine env --unset)"
    echo "false"
  fi
}
$ eval $(docker-machine-env-fixed foobar) && docker-machine regenerate-certs
Machine "foobar" has NOT been activated.

It's possible that just unsetting the environment variables would solve the problem (unless they default to localhost, I'm not sure how that works), but if you want to go full pickle I think that all three would be the best course of action.

@raeesiqbal
Exact same problem here, with docker-machine regenerate-certs, which nuked the previous machine that I'd been working on. Sounds like yours blew up too.

Yeah I actually had to cleanup everything and do a clean install and delete .docker directory to make it work again. I figured out afterwards that it had issues with the newly generated certificates. Which were not working for any of the machines I was trying to create or run.

Here is my workaround:

eval $(docker-machine env $MACHINE_NAME)
if [ "$(docker-machine active)" != "$MACHINE_NAME" ]; then
  echo "Activation failed";
  exit 1;
fi

@MichaelSp here is mine

eval $(docker-machine env $MACHINE_NAME || echo "exit $?")
Was this page helpful?
0 / 5 - 0 ratings

Related issues

jrz picture jrz  路  5Comments

BretFisher picture BretFisher  路  5Comments

duynguyenvan picture duynguyenvan  路  3Comments

huseyinbabal picture huseyinbabal  路  4Comments

masaeedu picture masaeedu  路  4Comments