Skip to content
This repository has been archived by the owner on Apr 11, 2022. It is now read-only.

Respect DOCKER_CONFIG environment variable (closes #88) #90

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 26 additions & 20 deletions pierone/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from .exceptions import ArtifactNotFound, Forbidden, Conflict, UnprocessableEntity
from .types import DockerImage
from .utils import get_user_friendly_user_name
from .utils import get_user_friendly_user_name, get_docker_config_path

adapter = requests.adapters.HTTPAdapter(pool_connections=10, pool_maxsize=10)
session = requests.Session()
Expand All @@ -21,7 +21,6 @@


class PierOne:

def __init__(self, url: str):
self.url = url if url.startswith("https://") else "https://" + url
self._access_token = get_token('pierone', ['uid'])
Expand Down Expand Up @@ -149,6 +148,21 @@ def mark_production_ready(self, image: DockerImage, incident_id: str):
)


def safe_load_json(path, default={}):
try:
with open(path, 'r') as fd:
return json.load(fd)
except Exception:
return default


def safe_dump_json(path, data):
os.makedirs(os.path.dirname(path), exist_ok=True)

with open(path, 'w') as fd:
json.dump(data, fd, indent=2)


# all the other paramaters are deprecated, but still here for compatibility
def docker_login(url, realm, name, user, password, token_url=None, use_keyring=True, prompt=False):
with Action('Getting OAuth2 token "{}"..'.format(name)):
Expand All @@ -159,12 +173,9 @@ def docker_login(url, realm, name, user, password, token_url=None, use_keyring=T
def docker_login_with_token(url, access_token):
'''Configure docker with existing OAuth2 access token'''

path = os.path.expanduser('~/.docker/config.json')
try:
with open(path) as fd:
dockercfg = json.load(fd)
except Exception:
dockercfg = {}
path = get_docker_config_path('config.json')
dockercfg = safe_load_json(path, {})

basic_auth = codecs.encode('oauth2:{}'.format(access_token).encode('utf-8'), 'base64').strip().decode('utf-8')

dockercfg['auths'] = dockercfg.get('auths', {})
Expand All @@ -177,9 +188,7 @@ def docker_login_with_token(url, access_token):
dockercfg['credHelpers'][hostname] = ""

with Action('Storing Docker client configuration in {}..'.format(path)):
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, 'w') as fd:
json.dump(dockercfg, fd, indent=2)
safe_dump_json(path, dockercfg)


def iid_auth():
Expand All @@ -192,20 +201,17 @@ def iid_auth():
def docker_login_with_iid(url):
'''Configure docker with IID auth'''

path = os.path.expanduser('~/.docker/config.json')
try:
with open(path) as fd:
dockercfg = json.load(fd)
except Exception:
dockercfg = {}
path = get_docker_config_path('config.json')
dockercfg = safe_load_json(path, {})

if 'auths' not in dockercfg:
dockercfg['auths'] = {}

dockercfg['auths'][url] = {'auth': iid_auth(),
'email': '[email protected]'}

with Action('Storing Docker client configuration in {}..'.format(path)):
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, 'w') as fd:
json.dump(dockercfg, fd)
safe_dump_json(path, dockercfg)


def request(url, path, access_token: str = None,
Expand Down
13 changes: 12 additions & 1 deletion pierone/utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import os

KNOWN_USERS = {
"credprov-cdp-controller-proxy_pierone-token": "[CDP]",
"credprov-cdp-controller-proxy-credentials-cdp_proxy-token": "[CDP]",
Expand All @@ -16,6 +18,15 @@ def get_user_friendly_user_name(long_user_name: str) -> str:
Try to make long user names more user friendly by mapping known long user names to short
versions.

IF the user name is not "known" it is return unchanged.
If the user name is not "known" it is return unchanged.
"""
return KNOWN_USERS.get(long_user_name, long_user_name)


def get_docker_config_path(filename: str) -> str:
"""
Return the path to a Docker config file.
"""
directory = os.environ.get('DOCKER_CONFIG', '~/.docker')
path = os.path.join(directory, filename)
return os.path.expanduser(path)
37 changes: 24 additions & 13 deletions tests/test_api.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import json
import os
import yaml

from unittest.mock import MagicMock, ANY

import yaml
import pytest

from pierone.api import docker_login, docker_login_with_iid, PierOne, get_latest_tag, image_exists
from pierone.exceptions import ArtifactNotFound, Forbidden, UnprocessableEntity, Conflict
from pierone.types import DockerImage
Expand All @@ -12,12 +14,18 @@


@pytest.fixture(autouse=True)
def valid_pierone_url(monkeypatch):
def valid_pierone_url(monkeypatch, tmpdir):
response = MagicMock()
response.text = 'Pier One API'
monkeypatch.setattr('requests.get', lambda *args, **kw: response)


@pytest.fixture(autouse=True)
def mock_docker_config_path(monkeypatch, tmpdir):
monkeypatch.setattr('pierone.api.get_docker_config_path',
lambda path: os.path.join(str(tmpdir), path))


@pytest.fixture(autouse=True)
def mock_get_token(monkeypatch):
monkeypatch.setattr('pierone.api.get_token', MagicMock(return_value="12377"))
Expand All @@ -31,11 +39,12 @@ def make_error_response(status_code: int):


def test_docker_login(monkeypatch, tmpdir):
monkeypatch.setattr('os.path.expanduser', lambda x: x.replace('~', str(tmpdir)))
monkeypatch.setattr('pierone.api.get_token', MagicMock(return_value='12377'))

docker_login('https://pierone.example.org', 'services', 'mytok',
'myuser', 'mypass', 'https://token.example.org', use_keyring=False)
path = os.path.expanduser('~/.docker/config.json')

path = os.path.join(str(tmpdir), 'config.json')
with open(path) as fd:
data = yaml.safe_load(fd)
assert {'auth': 'b2F1dGgyOjEyMzc3',
Expand All @@ -44,19 +53,18 @@ def test_docker_login(monkeypatch, tmpdir):


def test_docker_login_service_token(monkeypatch, tmpdir):
monkeypatch.setattr('os.path.expanduser', lambda x: x.replace('~', str(tmpdir)))
monkeypatch.setattr('tokens.get', lambda x: '12377')

docker_login('https://pierone.example.org', None, 'mytok', 'myuser', 'mypass', 'https://token.example.org')
path = os.path.expanduser('~/.docker/config.json')

path = os.path.join(str(tmpdir), 'config.json')
with open(path) as fd:
data = yaml.safe_load(fd)
assert {'auth': 'b2F1dGgyOjEyMzc3',
'email': '[email protected]'} == data.get('auths').get('https://pierone.example.org')


def test_docker_login_with_iid(monkeypatch, tmpdir):
monkeypatch.setattr('os.path.expanduser',
lambda x: x.replace('~', str(tmpdir)))
metaservice = MagicMock()
metaservice.text = '''TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNldGV0dXIgc2FkaXBzY2luZyBlbGl0ciwg
c2VkIGRpYW0gbm9udW15IGVpcm1vZCB0ZW1wb3IgaW52aWR1bnQgdXQgbGFib3JlIGV0IGRvbG9y
Expand All @@ -71,8 +79,10 @@ def test_docker_login_with_iid(monkeypatch, tmpdir):
aXBzdW0gZG9sb3Igc2l0IGFtZXQuCg=='''
monkeypatch.setattr('pierone.api.request',
MagicMock(return_value=metaservice))

docker_login_with_iid('https://pierone.example.org')
path = os.path.expanduser('~/.docker/config.json')

path = os.path.join(str(tmpdir), 'config.json')
with open(path) as fd:
data = yaml.safe_load(fd)
assert {'auth': 'aW5zdGFuY2UtaWRlbnRpdHktZG9jdW1lbnQ6VEc5eVpXMGdhWEJ6ZFcwZ1pHOXNiM0lnYzJsMElH'
Expand All @@ -94,9 +104,9 @@ def test_docker_login_with_iid(monkeypatch, tmpdir):


def test_keep_dockercfg_entries(monkeypatch, tmpdir):
monkeypatch.setattr('os.path.expanduser', lambda x: x.replace('~', str(tmpdir)))
monkeypatch.setattr('pierone.api.get_token', MagicMock(return_value='12377'))
path = os.path.expanduser('~/.docker/config.json')

path = os.path.join(str(tmpdir), 'config.json')

key = 'https://old.example.org'
existing_data = {
Expand All @@ -105,14 +115,15 @@ def test_keep_dockercfg_entries(monkeypatch, tmpdir):
'email': '[email protected]'
}
}
os.makedirs(os.path.dirname(path))

with open(path, 'w') as fd:
json.dump(existing_data, fd)

docker_login('https://pierone.example.org', 'services', 'mytok',
'myuser', 'mypass', 'https://token.example.org', use_keyring=False)

with open(path) as fd:
data = yaml.safe_load(fd)
data = json.load(fd)
assert {'auth': 'b2F1dGgyOjEyMzc3',
'email': '[email protected]'} == data.get('auths', {}).get('https://pierone.example.org')
assert existing_data.get(key) == data.get(key)
Expand Down
Loading