eval $(docker-machine env default) not working in iterm startup script - bash

I have a startup script for iterm that starts a docker vm if missing, and connects to it if it already exists.
iterm_startup.sh
#!/bin/bash
typeset cmnd="docker-machine ls --filter name='default' --filter state='stopped' | grep default"
typeset ret_code
echo "running startup script ===> ${cmnd}"
eval $cmnd
ret_code=$?
# If not 0, means docker vm has already started
if [ $ret_code != 0 ]; then
eval $(docker-machine env default)
# If 0, means defai;t docker vm not yet started
elif [ $ret_code == 0 ]; then
docker-machine start default
fi
When a docker machine exists, it goes into the block that runs eval $(docker-machine env default). However, when I go to the terminal, it still hasn't connected to the docker vm. I have to manually run eval $(docker-machine env default) in the shell again.
Can someone help me understand why eval $(docker-machine env default) doesn't work as expected in a script? :)

From the settings you showed, it looks like you're asking iTerm to "type in" the path to your script and run it as the first thing when a new terminal window opens. When that happens the script runs as a subprocess. If you look at what docker-machine env prints out it's just a set of export shell commands, so now you stumble on the general rule that subprocesses can't affect their parents' environments.
The simple answer is to change the command to "source" your script so that it runs in the context of the terminal's shell. Try changing your "send text at start" to
. ~/scripts/iterm_startup.sh
Looking at your script, I suspect you could make it much simpler using docker-machine status, and I suspect you need to do the "eval" step even if the machine isn't running yet.
MACHINE=default
if [ $(docker-machine status "$MACHINE" 2>&1) != "Running" ]; then
docker-machine start "$MACHINE"
fi
eval $(docker-machine env "$MACHINE")

Related

Setting environment variables in shell script OS X

I'm trying to create a Shell Script to automate my local dev environment. I need it start some processes (Redis, MongoDB, etc.), set the environment variables then start the local web server. I'm working on OS X El Capitan.
Everything is working so far, except the environment variables. Here is the script:
#!/bin/bash
# Starting the Redis Server
if pgrep "redis-server" > /dev/null
then
printf "Redis is already running.\n"
else
brew services start redis
fi
# Starting the Mongo Service
if pgrep "mongod" > /dev/null
then
printf "MongoDB is already running.\n"
else
brew services start mongodb
fi
# Starting the API Server
printf "\nStarting API Server...\n"
source path-to-file.env
pm2 start path-to-server.js --name="api" --watch --silent
# Starting the Auth Server
printf "\nStarting Auth Server...\n"
source path-to-file.env
pm2 start path-to-server.js --name="auth" --watch --silent
# Starting the Client Server
printf "\nStarting Local Client...\n"
source path-to-file.env
pm2 start path-to-server.js --name="client" --watch --silent
The .env file is using the format export VARIABLE="value"
The environment variables are just not being set at all. But, if I run the exact command source path-to-file.env before running the script then it works. I'm wondering why the command would work independently but not inside the shell script.
Any help would be appreciated.
When you execute a script, it executes in a subshell, and its environment settings are lost when the subshell exits. If you want to configure your interactive shell from a script, you must source the script in your interactive shell.
$ source start-local.sh
Now the environment should appear in your interactive shell. If you want that environment to be inherited by subshells, you must also export any variables that will be required. So, for instance, in path-to-file.env, you'd want lines like:
export MY_IMPORTANT_PATH_VAR="/example/blah"

Eval in docker-machine: terminal vs shell script

I'm trying to run a simple shell script to automate changing docker-machine environments. The problem is this, when I run the following command directly in the Mac terminal the following is outputted:
eval $(docker-machine env default)
docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
default * digitalocean Running tcp://***.**.***.***:**** v1.12.0
So basically what you would expect, however when I run the following .sh script:
#!/usr/bin/env bash
eval $(docker-machine env default)
The output is:
./run.sh
docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
default digitalocean Running tcp://***.**.***.***:**** v1.12.0
So basically, it is not setting it as active and I cannot access it.
Has anyone run into this issue before and knows how to solve it? Seems really strange to me, have got pretty much everything else running and automated apart from this facet.
Cheers, Aaron
I think you need to source your shell script
source ./myscript.sh
as the exports in the eval are being returned to the process you started to run the shell in and then being disposed of. These need to go to the parent e.g. login shell
Consider a.sh
#!/bin/bash
eval $(echo 'export a=123')
export b=234
when run in two ways
$ ./a.sh
$ echo $a
$ echo $b
$ source a.sh
$ echo $a
123
$ echo $b
234
$

Scripting Docker, Not Connected After Running Script?

So I have a script that looks like this:
#!/bin/bash
if [ $1 ]; then
docker-machine start $1
docker-machine env $1
eval $(docker-machine env $1)
docker ps -a
fi
Once it has run though, the scope of these commands seem to be over. For instance I don't have a connection to the docker-machine once the script has run, but I'd like to script this part out so I can have access to it.
For instance, after running this script ("./script.sh") I still can't run "docker ps -a".
What's the reason this happens and how could I get it to effectively be connected to after executing this script?
A script (or any other process) cannot modify the environment of its parent process. That is precisely why docker-machine env emits shell code that needs to be evaluated with eval.
If you want these variables accessible outside of your script, you would need to arrange to run eval $(docker-machine env <whatever>) in your current shell.

How do I undo the command $ eval "$(docker-machine env blog)"

I think that command redirected $ docker commands to the docker machine. Now all my docker commands are giving me an error FATA[0000] Couldn't read ca cert... follwed by the path to the docker-machine I created. How can I fix my shell?
What you are looking for is:
eval "$(docker-machine env -u)"
It will unset the DOCKER_* variables.
For the record, here's the output of docker-machine env -u:
unset DOCKER_TLS_VERIFY
unset DOCKER_HOST
unset DOCKER_CERT_PATH
unset DOCKER_MACHINE_NAME
You could also restart your shell. This will drop the variables that minkube docker-env exports.
I can see that this is an old post but if someone else runs into this issue, who is new to docker like me this can help. By typing:
eval $(docker-machine env nameOfVm)
you are setting your current shell to use docker in that docker-machine. You can check if you type docker-machine ls
that under active tab, that status is changed from - to * for that machine. You can also check which machine is active by running docker-machine active.
If you want to undo eval, just run:
eval $(docker-machine env -u)
and it will unset variables for active machine (You don't have to specify the name of the machine). This is all under macOS but I think it should be same on linux as well.
You can read more about this here:
Docker documentation: docker-machine env
I had been searching for an answer to this for quite awhile. Shortly after posting the question on stackoverflow I realized typing in to the terminal the export commands docker gives on startup resolved my issue.
To connect the Docker client to the Docker daemon, please set:
export DOCKER_HOST=tcp:// some IP address
export DOCKER_CERT_PATH= some file path
export DOCKER_TLS_VERIFY=1
All you have to do is run
docker-machine env machine-name
Then, copy and run the last segment in the output to set or remove the env variables.
Which looks like this in Windows :
eval $("C:\Program Files\Docker Toolbox\docker-machine.exe" env machine-name)
If it's set already, docker adds a "-u" at the tail to make the task easy.
like this in Windows :
eval $("C:\Program Files\Docker Toolbox\docker-machine.exe" env -u)
That's all.

Surrounding bash command with $(<command>)

I was reading up on docker-machine (https://github.com/docker/machine) when I noticed this instruction
$ docker $(docker-machine config dev) run busybox echo hello world
I was curious what the $(docker-machine config dev) part did, particularly, what is the point of the $() bit? docker-machine config dev is a command, so does executing it with the $() do some bash magic?
It produces a single variable to be passed as argument to program. It's like doing t=$(echo hello) will make $t equal to "hello". You can achieve the same by doing t=$(command) and then docker $t other-args

Resources