Add support for DOCKER_CONFIG/--config to specific config file dir

Carry #11675

Aside from what #11675 says, to me a key usecase for this is to support
more than one Docker cli running at the same time but each may have its
own set of config files.

Signed-off-by: Doug Davis <dug@us.ibm.com>
This commit is contained in:
Doug Davis 2015-04-28 08:00:18 -07:00
parent 0afd7bde02
commit daced1d303
9 changed files with 132 additions and 15 deletions

View file

@ -7,13 +7,11 @@ import (
"fmt"
"io"
"net/http"
"path/filepath"
"reflect"
"strings"
"text/template"
"github.com/docker/docker/cliconfig"
"github.com/docker/docker/pkg/homedir"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/sockets"
"github.com/docker/docker/pkg/term"
@ -212,7 +210,7 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, keyFile string, proto, a
}
sockets.ConfigureTCPTransport(tr, proto, addr)
configFile, e := cliconfig.Load(filepath.Join(homedir.Get(), ".docker"))
configFile, e := cliconfig.Load(cliconfig.ConfigDir())
if e != nil {
fmt.Fprintf(err, "WARNING: Error loading config file:%v\n", e)
}

View file

@ -25,9 +25,24 @@ const (
)
var (
configDir = os.Getenv("DOCKER_CONFIG")
ErrConfigFileMissing = errors.New("The Auth config file is missing")
)
func init() {
if configDir == "" {
configDir = filepath.Join(homedir.Get(), ".docker")
}
}
func ConfigDir() string {
return configDir
}
func SetConfigDir(dir string) {
configDir = dir
}
// Registry Auth Info
type AuthConfig struct {
Username string `json:"username,omitempty"`
@ -56,7 +71,7 @@ func NewConfigFile(fn string) *ConfigFile {
// FIXME: use the internal golang config parser
func Load(configDir string) (*ConfigFile, error) {
if configDir == "" {
configDir = filepath.Join(homedir.Get(), ".docker")
configDir = ConfigDir()
}
configFile := ConfigFile{

View file

@ -13,8 +13,8 @@ import (
"github.com/Sirupsen/logrus"
apiserver "github.com/docker/docker/api/server"
"github.com/docker/docker/autogen/dockerversion"
"github.com/docker/docker/cliconfig"
"github.com/docker/docker/daemon"
"github.com/docker/docker/pkg/homedir"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/pidfile"
"github.com/docker/docker/pkg/signal"
@ -39,7 +39,7 @@ func init() {
func migrateKey() (err error) {
// Migrate trust key if exists at ~/.docker/key.json and owned by current user
oldPath := filepath.Join(homedir.Get(), ".docker", defaultTrustKeyFile)
oldPath := filepath.Join(cliconfig.ConfigDir(), defaultTrustKeyFile)
newPath := filepath.Join(getDaemonConfDir(), defaultTrustKeyFile)
if _, statErr := os.Stat(newPath); os.IsNotExist(statErr) && currentUserIsOwner(oldPath) {
defer func() {

View file

@ -10,6 +10,7 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api/client"
"github.com/docker/docker/autogen/dockerversion"
"github.com/docker/docker/cliconfig"
"github.com/docker/docker/opts"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/reexec"
@ -43,6 +44,10 @@ func main() {
return
}
if *flConfigDir != "" {
cliconfig.SetConfigDir(*flConfigDir)
}
if *flLogLevel != "" {
lvl, err := logrus.ParseLevel(*flLogLevel)
if err != nil {

View file

@ -7,8 +7,8 @@ import (
"runtime"
"sort"
"github.com/docker/docker/cliconfig"
"github.com/docker/docker/opts"
"github.com/docker/docker/pkg/homedir"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/tlsconfig"
)
@ -73,19 +73,20 @@ var (
func init() {
if dockerCertPath == "" {
dockerCertPath = filepath.Join(homedir.Get(), ".docker")
dockerCertPath = cliconfig.ConfigDir()
}
}
func getDaemonConfDir() string {
// TODO: update for Windows daemon
if runtime.GOOS == "windows" {
return filepath.Join(homedir.Get(), ".docker")
return cliconfig.ConfigDir()
}
return "/etc/docker"
}
var (
flConfigDir = flag.String([]string{"-config"}, cliconfig.ConfigDir(), "Location of client config files")
flVersion = flag.Bool([]string{"v", "-version"}, false, "Print version information and quit")
flDaemon = flag.Bool([]string{"d", "-daemon"}, false, "Enable daemon mode")
flDebug = flag.Bool([]string{"D", "-debug"}, false, "Enable debug mode")
@ -105,7 +106,7 @@ func setDefaultConfFlag(flag *string, def string) {
if *flDaemon {
*flag = filepath.Join(getDaemonConfDir(), def)
} else {
*flag = filepath.Join(homedir.Get(), ".docker", def)
*flag = filepath.Join(cliconfig.ConfigDir(), def)
}
}
}

View file

@ -10,7 +10,7 @@ parent = "smn_cli"
# Using the command line
> **Note:** if you are using a remote Docker daemon, such as Boot2Docker,
> **Note:** If you are using a remote Docker daemon, such as Boot2Docker,
> then _do not_ type the `sudo` before the `docker` commands shown in the
> documentation's examples.
@ -38,6 +38,7 @@ the [installation](/installation) instructions for your operating system.
For easy reference, the following list of environment variables are supported
by the `docker` command line:
* `DOCKER_CONFIG` The location of your client configuration files.
* `DOCKER_CERT_PATH` The location of your authentication keys.
* `DOCKER_DRIVER` The graph driver to use.
* `DOCKER_HOST` Daemon socket to connect to.
@ -60,10 +61,21 @@ variables.
## Configuration files
The Docker command line stores its configuration files in a directory called
`.docker` within your `HOME` directory. Docker manages most of the files in
`.docker` and you should not modify them. However, you *can modify* the
`.docker/config.json` file to control certain aspects of how the `docker`
By default, the Docker command line stores its configuration files in a
directory called `.docker` within your `HOME` directory. However, you can
specify a different location via the `DOCKER_CONFIG` environment variable
or the `--config` command line option. If both are specified, then the
`--config` option overrides the `DOCKER_CONFIG` environment variable.
For example:
docker --config ~/testconfigs/ ps
Instructs Docker to use the configuration files in your `~/testconfigs/`
directory when running the `ps` command.
Docker manages most of the files in the configuration directory
and you should not modify them. However, you *can modify* the
`config.json` file to control certain aspects of how the `docker`
command behaves.
Currently, you can modify the `docker` command behavior using environment

View file

@ -18,6 +18,7 @@ parent = "smn_cli"
--api-cors-header="" Set CORS headers in the remote API
-b, --bridge="" Attach containers to a network bridge
--bip="" Specify network bridge IP
--config=~/.docker Location of client config files
-D, --debug=false Enable debug mode
-d, --daemon=false Enable daemon mode
--default-gateway="" Container default gateway IPv4 address

View file

@ -64,3 +64,85 @@ func (s *DockerSuite) TestConfigHttpHeader(c *check.C) {
c.Fatalf("Missing/bad header: %q\nout:%v", headers, out)
}
}
func (s *DockerSuite) TestConfigDir(c *check.C) {
cDir, _ := ioutil.TempDir("", "fake-home")
// First make sure pointing to empty dir doesn't generate an error
cmd := exec.Command(dockerBinary, "--config", cDir, "ps")
out, rc, err := runCommandWithOutput(cmd)
if rc != 0 || err != nil {
c.Fatalf("ps1 didn't work:\nrc:%d\nout%s\nerr:%v", rc, out, err)
}
// Test with env var too
cmd = exec.Command(dockerBinary, "ps")
cmd.Env = append(os.Environ(), "DOCKER_CONFIG="+cDir)
out, rc, err = runCommandWithOutput(cmd)
if rc != 0 || err != nil {
c.Fatalf("ps2 didn't work:\nrc:%d\nout%s\nerr:%v", rc, out, err)
}
// Start a server so we can check to see if the config file was
// loaded properly
var headers map[string][]string
server := httptest.NewServer(http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
headers = r.Header
}))
defer server.Close()
// Create a dummy config file in our new config dir
data := `{
"HttpHeaders": { "MyHeader": "MyValue" }
}`
tmpCfg := filepath.Join(cDir, "config.json")
err = ioutil.WriteFile(tmpCfg, []byte(data), 0600)
if err != nil {
c.Fatalf("Err creating file(%s): %v", tmpCfg, err)
}
cmd = exec.Command(dockerBinary, "--config", cDir, "-H="+server.URL[7:], "ps")
out, _, _ = runCommandWithOutput(cmd)
if headers["Myheader"] == nil || headers["Myheader"][0] != "MyValue" {
c.Fatalf("ps3 - Missing header: %q\nout:%v", headers, out)
}
// Reset headers and try again using env var this time
headers = map[string][]string{}
cmd = exec.Command(dockerBinary, "-H="+server.URL[7:], "ps")
cmd.Env = append(os.Environ(), "DOCKER_CONFIG="+cDir)
out, _, _ = runCommandWithOutput(cmd)
if headers["Myheader"] == nil || headers["Myheader"][0] != "MyValue" {
c.Fatalf("ps4 - Missing header: %q\nout:%v", headers, out)
}
// Reset headers and make sure flag overrides the env var
headers = map[string][]string{}
cmd = exec.Command(dockerBinary, "--config", cDir, "-H="+server.URL[7:], "ps")
cmd.Env = append(os.Environ(), "DOCKER_CONFIG=MissingDir")
out, _, _ = runCommandWithOutput(cmd)
if headers["Myheader"] == nil || headers["Myheader"][0] != "MyValue" {
c.Fatalf("ps5 - Missing header: %q\nout:%v", headers, out)
}
// Reset headers and make sure flag overrides the env var.
// Almost same as previous but make sure the "MissingDir" isn't
// ignore - we don't want to default back to the env var.
headers = map[string][]string{}
cmd = exec.Command(dockerBinary, "--config", "MissingDir", "-H="+server.URL[7:], "ps")
cmd.Env = append(os.Environ(), "DOCKER_CONFIG="+cDir)
out, _, _ = runCommandWithOutput(cmd)
if headers["Myheader"] != nil {
c.Fatalf("ps6 - Headers are there but shouldn't be: %q\nout:%v", headers, out)
}
}

View file

@ -35,6 +35,9 @@ To see the man page for a command run **man docker <command>**.
**--bip**=""
Use the provided CIDR notation address for the dynamically created bridge (docker0); Mutually exclusive of \-b
**--config**=""
Specifies the location of the Docker client configuration files. The default is '~/.docker'.
**-D**, **--debug**=*true*|*false*
Enable debug mode. Default is false.