mirror of https://github.com/docker/docker-py.git
Merge pull request #802 from docker/785-docker_config_env
Use DOCKER_CONFIG environment variable to look up auth config
This commit is contained in:
commit
baaa3e3b1a
|
|
@ -13,7 +13,6 @@
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import fileinput
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
@ -132,78 +131,79 @@ def parse_auth(entries):
|
||||||
return conf
|
return conf
|
||||||
|
|
||||||
|
|
||||||
|
def find_config_file(config_path=None):
|
||||||
|
environment_path = os.path.join(
|
||||||
|
os.environ.get('DOCKER_CONFIG'),
|
||||||
|
os.path.basename(DOCKER_CONFIG_FILENAME)
|
||||||
|
) if os.environ.get('DOCKER_CONFIG') else None
|
||||||
|
|
||||||
|
paths = [
|
||||||
|
config_path, # 1
|
||||||
|
environment_path, # 2
|
||||||
|
os.path.join(os.path.expanduser('~'), DOCKER_CONFIG_FILENAME), # 3
|
||||||
|
os.path.join(
|
||||||
|
os.path.expanduser('~'), LEGACY_DOCKER_CONFIG_FILENAME
|
||||||
|
) # 4
|
||||||
|
]
|
||||||
|
|
||||||
|
for path in paths:
|
||||||
|
if path and os.path.exists(path):
|
||||||
|
return path
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def load_config(config_path=None):
|
def load_config(config_path=None):
|
||||||
"""
|
"""
|
||||||
Loads authentication data from a Docker configuration file in the given
|
Loads authentication data from a Docker configuration file in the given
|
||||||
root directory or if config_path is passed use given path.
|
root directory or if config_path is passed use given path.
|
||||||
|
Lookup priority:
|
||||||
|
explicit config_path parameter > DOCKER_CONFIG environment variable >
|
||||||
|
~/.docker/config.json > ~/.dockercfg
|
||||||
"""
|
"""
|
||||||
conf = {}
|
|
||||||
data = None
|
|
||||||
|
|
||||||
# Prefer ~/.docker/config.json.
|
config_file = find_config_file(config_path)
|
||||||
config_file = config_path or os.path.join(os.path.expanduser('~'),
|
|
||||||
DOCKER_CONFIG_FILENAME)
|
|
||||||
|
|
||||||
log.debug("Trying {0}".format(config_file))
|
if not config_file:
|
||||||
|
|
||||||
if os.path.exists(config_file):
|
|
||||||
try:
|
|
||||||
with open(config_file) as f:
|
|
||||||
for section, data in six.iteritems(json.load(f)):
|
|
||||||
if section != 'auths':
|
|
||||||
continue
|
|
||||||
log.debug("Found 'auths' section")
|
|
||||||
return parse_auth(data)
|
|
||||||
log.debug("Couldn't find 'auths' section")
|
|
||||||
except (IOError, KeyError, ValueError) as e:
|
|
||||||
# Likely missing new Docker config file or it's in an
|
|
||||||
# unknown format, continue to attempt to read old location
|
|
||||||
# and format.
|
|
||||||
log.debug(e)
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
log.debug("File doesn't exist")
|
log.debug("File doesn't exist")
|
||||||
|
|
||||||
config_file = config_path or os.path.join(os.path.expanduser('~'),
|
|
||||||
LEGACY_DOCKER_CONFIG_FILENAME)
|
|
||||||
|
|
||||||
log.debug("Trying {0}".format(config_file))
|
|
||||||
|
|
||||||
if not os.path.exists(config_file):
|
|
||||||
log.debug("File doesn't exist - returning empty config")
|
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
log.debug("Attempting to parse as JSON")
|
|
||||||
try:
|
try:
|
||||||
with open(config_file) as f:
|
with open(config_file) as f:
|
||||||
return parse_auth(json.load(f))
|
data = json.load(f)
|
||||||
except Exception as e:
|
if data.get('auths'):
|
||||||
|
log.debug("Found 'auths' section")
|
||||||
|
return parse_auth(data)
|
||||||
|
else:
|
||||||
|
log.debug("Couldn't find 'auths' section")
|
||||||
|
f.seek(0)
|
||||||
|
return parse_auth(json.load(f))
|
||||||
|
except (IOError, KeyError, ValueError) as e:
|
||||||
|
# Likely missing new Docker config file or it's in an
|
||||||
|
# unknown format, continue to attempt to read old location
|
||||||
|
# and format.
|
||||||
log.debug(e)
|
log.debug(e)
|
||||||
pass
|
|
||||||
|
|
||||||
# If that fails, we assume the configuration file contains a single
|
|
||||||
# authentication token for the public registry in the following format:
|
|
||||||
#
|
|
||||||
# auth = AUTH_TOKEN
|
|
||||||
# email = email@domain.com
|
|
||||||
log.debug("Attempting to parse legacy auth file format")
|
log.debug("Attempting to parse legacy auth file format")
|
||||||
try:
|
try:
|
||||||
data = []
|
data = []
|
||||||
for line in fileinput.input(config_file):
|
with open(config_file) as f:
|
||||||
data.append(line.strip().split(' = ')[1])
|
for line in f.readlines():
|
||||||
if len(data) < 2:
|
data.append(line.strip().split(' = ')[1])
|
||||||
# Not enough data
|
if len(data) < 2:
|
||||||
raise errors.InvalidConfigFile(
|
# Not enough data
|
||||||
'Invalid or empty configuration file!')
|
raise errors.InvalidConfigFile(
|
||||||
|
'Invalid or empty configuration file!'
|
||||||
|
)
|
||||||
|
|
||||||
username, password = decode_auth(data[0])
|
username, password = decode_auth(data[0])
|
||||||
conf[INDEX_NAME] = {
|
return {
|
||||||
'username': username,
|
INDEX_NAME: {
|
||||||
'password': password,
|
'username': username,
|
||||||
'email': data[1],
|
'password': password,
|
||||||
'serveraddress': INDEX_URL,
|
'email': data[1],
|
||||||
|
'serveraddress': INDEX_URL,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return conf
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.debug(e)
|
log.debug(e)
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -2387,7 +2387,7 @@ class DockerClientTest(Cleanup, base.BaseTestCase):
|
||||||
f.write('auth = {0}\n'.format(auth_))
|
f.write('auth = {0}\n'.format(auth_))
|
||||||
f.write('email = sakuya@scarlet.net')
|
f.write('email = sakuya@scarlet.net')
|
||||||
cfg = docker.auth.load_config(dockercfg_path)
|
cfg = docker.auth.load_config(dockercfg_path)
|
||||||
self.assertTrue(docker.auth.INDEX_NAME in cfg)
|
assert docker.auth.INDEX_NAME in cfg
|
||||||
self.assertNotEqual(cfg[docker.auth.INDEX_NAME], None)
|
self.assertNotEqual(cfg[docker.auth.INDEX_NAME], None)
|
||||||
cfg = cfg[docker.auth.INDEX_NAME]
|
cfg = cfg[docker.auth.INDEX_NAME]
|
||||||
self.assertEqual(cfg['username'], 'sakuya')
|
self.assertEqual(cfg['username'], 'sakuya')
|
||||||
|
|
@ -2412,10 +2412,10 @@ class DockerClientTest(Cleanup, base.BaseTestCase):
|
||||||
}
|
}
|
||||||
|
|
||||||
with open(dockercfg_path, 'w') as f:
|
with open(dockercfg_path, 'w') as f:
|
||||||
f.write(json.dumps(config))
|
json.dump(config, f)
|
||||||
|
|
||||||
cfg = docker.auth.load_config(dockercfg_path)
|
cfg = docker.auth.load_config(dockercfg_path)
|
||||||
self.assertTrue(registry in cfg)
|
assert registry in cfg
|
||||||
self.assertNotEqual(cfg[registry], None)
|
self.assertNotEqual(cfg[registry], None)
|
||||||
cfg = cfg[registry]
|
cfg = cfg[registry]
|
||||||
self.assertEqual(cfg['username'], 'sakuya')
|
self.assertEqual(cfg['username'], 'sakuya')
|
||||||
|
|
@ -2423,6 +2423,33 @@ class DockerClientTest(Cleanup, base.BaseTestCase):
|
||||||
self.assertEqual(cfg['email'], 'sakuya@scarlet.net')
|
self.assertEqual(cfg['email'], 'sakuya@scarlet.net')
|
||||||
self.assertEqual(cfg.get('auth'), None)
|
self.assertEqual(cfg.get('auth'), None)
|
||||||
|
|
||||||
|
def test_load_config_custom_config_env(self):
|
||||||
|
folder = tempfile.mkdtemp()
|
||||||
|
self.addCleanup(shutil.rmtree, folder)
|
||||||
|
|
||||||
|
dockercfg_path = os.path.join(folder, 'config.json')
|
||||||
|
registry = 'https://your.private.registry.io'
|
||||||
|
auth_ = base64.b64encode(b'sakuya:izayoi').decode('ascii')
|
||||||
|
config = {
|
||||||
|
registry: {
|
||||||
|
'auth': '{0}'.format(auth_),
|
||||||
|
'email': 'sakuya@scarlet.net'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
with open(dockercfg_path, 'w') as f:
|
||||||
|
json.dump(config, f)
|
||||||
|
|
||||||
|
with mock.patch.dict(os.environ, {'DOCKER_CONFIG': folder}):
|
||||||
|
cfg = docker.auth.load_config(None)
|
||||||
|
assert registry in cfg
|
||||||
|
self.assertNotEqual(cfg[registry], None)
|
||||||
|
cfg = cfg[registry]
|
||||||
|
self.assertEqual(cfg['username'], 'sakuya')
|
||||||
|
self.assertEqual(cfg['password'], 'izayoi')
|
||||||
|
self.assertEqual(cfg['email'], 'sakuya@scarlet.net')
|
||||||
|
self.assertEqual(cfg.get('auth'), None)
|
||||||
|
|
||||||
def test_tar_with_excludes(self):
|
def test_tar_with_excludes(self):
|
||||||
dirs = [
|
dirs = [
|
||||||
'foo',
|
'foo',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue