Skip to content

Commit

Permalink
Add x auth (#215)
Browse files Browse the repository at this point in the history
  • Loading branch information
Christian Barra committed Apr 8, 2018
1 parent ef16437 commit 684bd3f
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGES/215.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Feature: Add support for registry-auth when you create a service.
34 changes: 31 additions & 3 deletions aiodocker/services.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
import json
from typing import Mapping, List, Any, Union, AsyncIterator
from typing import (
Mapping, List,
Any,
Union,
AsyncIterator,
Optional,
MutableMapping
)
from .multiplexed import multiplexed_result
from .utils import clean_map, clean_networks, clean_filters, format_env
from .utils import (
clean_map,
clean_networks,
clean_filters,
format_env,
compose_auth_header
)


class DockerServices(object):
Expand Down Expand Up @@ -40,7 +53,9 @@ async def create(self,
update_config: Mapping=None,
rollback_config: Mapping=None,
networks: List=None,
endpoint_spec: Mapping=None
endpoint_spec: Mapping=None,
auth: Optional[Union[MutableMapping, str, bytes]]=None,
registry: str=None
) -> Mapping[str, Any]:
"""
Create a service
Expand All @@ -54,6 +69,9 @@ async def create(self,
rollback_config: rollback strategy of the service
networks: array of network names/IDs to attach the service to
endpoint_spec: ports to expose
auth: authentication information, can be a string, dict or bytes
registry: used when auth is specified, it provides domain/IP of
the registry without a protocol
Returns:
a dict with info of the created service
Expand All @@ -64,13 +82,22 @@ async def create(self,
"Missing mandatory Image key in ContainerSpec"
)

if auth and registry is None:
raise KeyError(
"When auth is specified you need to specifiy also the registry"
)

# from {"key":"value"} to ["key=value"]
if "Env" in task_template["ContainerSpec"]:
task_template["ContainerSpec"]["Env"] = [
format_env(k, v)
for k, v in task_template["ContainerSpec"]["Env"].items()
]

headers = None
if auth:
headers = {"X-Registry-Auth": compose_auth_header(auth, registry)}

config = {
"TaskTemplate": task_template,
"Name": name,
Expand All @@ -88,6 +115,7 @@ async def create(self,
"services/create",
method="POST",
data=data,
headers=headers,
)
return response

Expand Down
3 changes: 1 addition & 2 deletions aiodocker/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,6 @@ def compose_auth_header(auth: Union[MutableMapping, str, bytes],
if registry_addr:
auth['serveraddress'] = registry_addr
auth_json = json.dumps(auth).encode('utf-8')
auth = base64.b64encode(auth_json).decode('ascii')
elif isinstance(auth, (str, bytes)):
# Parse simple "username:password"-formatted strings
# and attach the server address specified.
Expand All @@ -283,8 +282,8 @@ def compose_auth_header(auth: Union[MutableMapping, str, bytes],
"serveraddress": registry_addr,
}
auth_json = json.dumps(config).encode('utf-8')
auth = base64.b64encode(auth_json).decode('ascii')
else:
raise TypeError(
"auth must be base64 encoded string/bytes or a dictionary")
auth = base64.b64encode(auth_json).decode('ascii')
return auth
32 changes: 32 additions & 0 deletions tests/test_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,35 @@ async def test_service_create_error(swarm):
name=name,
task_template=TaskTemplate,
)


@pytest.mark.asyncio
async def test_service_create_service_with_auth(swarm):
name = "service-test-with-auth"
TaskTemplate = {
"ContainerSpec": {
"Image": "redis",
},
}
assert await swarm.services.create(
name=name,
task_template=TaskTemplate,
auth={"username": "username", "password": "password"},
registry="random.registry.com"
)


@pytest.mark.asyncio
async def test_service_create_error_for_missing_registry(swarm):
name = "service-test-error-with-auth"
TaskTemplate = {
"ContainerSpec": {
"Image": "redis",
},
}
with pytest.raises(KeyError):
await swarm.services.create(
name=name,
task_template=TaskTemplate,
auth={"username": "username", "password": "password"}
)

0 comments on commit 684bd3f

Please sign in to comment.