Private images support in create_service / update_service

Refactor auth header computation

Add tasks methods and documentation.

Signed-off-by: Joffrey F <joffrey@docker.com>
This commit is contained in:
Joffrey F 2016-08-22 19:12:27 -07:00
parent 7d5a1eeb7a
commit 775b581c04
6 changed files with 91 additions and 38 deletions

View File

@ -166,28 +166,10 @@ class ImageApiMixin(object):
headers = {} headers = {}
if utils.compare_version('1.5', self._version) >= 0: if utils.compare_version('1.5', self._version) >= 0:
# If we don't have any auth data so far, try reloading the config
# file one more time in case anything showed up in there.
if auth_config is None: if auth_config is None:
log.debug('Looking for auth config') header = auth.get_config_header(self, registry)
if not self._auth_configs: if header:
log.debug( headers['X-Registry-Auth'] = header
"No auth config in memory - loading from filesystem"
)
self._auth_configs = auth.load_config()
authcfg = auth.resolve_authconfig(self._auth_configs, registry)
# Do not fail here if no authentication exists for this
# specific registry as we can have a readonly pull. Just
# put the header if we can.
if authcfg:
log.debug('Found auth config')
# auth_config needs to be a dict in the format used by
# auth.py username , password, serveraddress, email
headers['X-Registry-Auth'] = auth.encode_header(
authcfg
)
else:
log.debug('No auth config found')
else: else:
log.debug('Sending supplied auth config') log.debug('Sending supplied auth config')
headers['X-Registry-Auth'] = auth.encode_header(auth_config) headers['X-Registry-Auth'] = auth.encode_header(auth_config)
@ -222,21 +204,10 @@ class ImageApiMixin(object):
headers = {} headers = {}
if utils.compare_version('1.5', self._version) >= 0: if utils.compare_version('1.5', self._version) >= 0:
# If we don't have any auth data so far, try reloading the config
# file one more time in case anything showed up in there.
if auth_config is None: if auth_config is None:
log.debug('Looking for auth config') header = auth.get_config_header(self, registry)
if not self._auth_configs: if header:
log.debug( headers['X-Registry-Auth'] = header
"No auth config in memory - loading from filesystem"
)
self._auth_configs = auth.load_config()
authcfg = auth.resolve_authconfig(self._auth_configs, registry)
# Do not fail here if no authentication exists for this
# specific registry as we can have a readonly pull. Just
# put the header if we can.
if authcfg:
headers['X-Registry-Auth'] = auth.encode_header(authcfg)
else: else:
log.debug('Sending supplied auth config') log.debug('Sending supplied auth config')
headers['X-Registry-Auth'] = auth.encode_header(auth_config) headers['X-Registry-Auth'] = auth.encode_header(auth_config)

View File

@ -1,4 +1,6 @@
from .. import errors
from .. import utils from .. import utils
from ..auth import auth
class ServiceApiMixin(object): class ServiceApiMixin(object):
@ -8,6 +10,16 @@ class ServiceApiMixin(object):
update_config=None, networks=None, endpoint_config=None update_config=None, networks=None, endpoint_config=None
): ):
url = self._url('/services/create') url = self._url('/services/create')
headers = {}
image = task_template.get('ContainerSpec', {}).get('Image', None)
if image is None:
raise errors.DockerException(
'Missing mandatory Image key in ContainerSpec'
)
registry, repo_name = auth.resolve_repository_name(image)
auth_header = auth.get_config_header(self, registry)
if auth_header:
headers['X-Registry-Auth'] = auth_header
data = { data = {
'Name': name, 'Name': name,
'Labels': labels, 'Labels': labels,
@ -17,7 +29,9 @@ class ServiceApiMixin(object):
'Networks': networks, 'Networks': networks,
'Endpoint': endpoint_config 'Endpoint': endpoint_config
} }
return self._result(self._post_json(url, data=data), True) return self._result(
self._post_json(url, data=data, headers=headers), True
)
@utils.minimum_version('1.24') @utils.minimum_version('1.24')
@utils.check_resource @utils.check_resource
@ -25,6 +39,12 @@ class ServiceApiMixin(object):
url = self._url('/services/{0}', service) url = self._url('/services/{0}', service)
return self._result(self._get(url), True) return self._result(self._get(url), True)
@utils.minimum_version('1.24')
@utils.check_resource
def inspect_task(self, task):
url = self._url('/tasks/{0}', task)
return self._result(self._get(url), True)
@utils.minimum_version('1.24') @utils.minimum_version('1.24')
@utils.check_resource @utils.check_resource
def remove_service(self, service): def remove_service(self, service):
@ -41,6 +61,14 @@ class ServiceApiMixin(object):
url = self._url('/services') url = self._url('/services')
return self._result(self._get(url, params=params), True) return self._result(self._get(url, params=params), True)
@utils.minimum_version('1.24')
def tasks(self, filters=None):
params = {
'filters': utils.convert_filters(filters) if filters else None
}
url = self._url('/tasks')
return self._result(self._get(url, params=params), True)
@utils.minimum_version('1.24') @utils.minimum_version('1.24')
@utils.check_resource @utils.check_resource
def update_service(self, service, version, task_template=None, name=None, def update_service(self, service, version, task_template=None, name=None,
@ -48,6 +76,7 @@ class ServiceApiMixin(object):
networks=None, endpoint_config=None): networks=None, endpoint_config=None):
url = self._url('/services/{0}/update', service) url = self._url('/services/{0}/update', service)
data = {} data = {}
headers = {}
if name is not None: if name is not None:
data['Name'] = name data['Name'] = name
if labels is not None: if labels is not None:
@ -55,6 +84,12 @@ class ServiceApiMixin(object):
if mode is not None: if mode is not None:
data['Mode'] = mode data['Mode'] = mode
if task_template is not None: if task_template is not None:
image = task_template.get('ContainerSpec', {}).get('Image', None)
if image is not None:
registry, repo_name = auth.resolve_repository_name(image)
auth_header = auth.get_config_header(self, registry)
if auth_header:
headers['X-Registry-Auth'] = auth_header
data['TaskTemplate'] = task_template data['TaskTemplate'] = task_template
if update_config is not None: if update_config is not None:
data['UpdateConfig'] = update_config data['UpdateConfig'] = update_config
@ -63,6 +98,8 @@ class ServiceApiMixin(object):
if endpoint_config is not None: if endpoint_config is not None:
data['Endpoint'] = endpoint_config data['Endpoint'] = endpoint_config
resp = self._post_json(url, data=data, params={'version': version}) resp = self._post_json(
url, data=data, params={'version': version}, headers=headers
)
self._raise_for_status(resp) self._raise_for_status(resp)
return True return True

View File

@ -51,6 +51,26 @@ def resolve_index_name(index_name):
return index_name return index_name
def get_config_header(client, registry):
log.debug('Looking for auth config')
if not client._auth_configs:
log.debug(
"No auth config in memory - loading from filesystem"
)
client._auth_configs = load_config()
authcfg = resolve_authconfig(client._auth_configs, registry)
# Do not fail here if no authentication exists for this
# specific registry as we can have a readonly pull. Just
# put the header if we can.
if authcfg:
log.debug('Found auth config')
# auth_config needs to be a dict in the format used by
# auth.py username , password, serveraddress, email
return encode_header(authcfg)
log.debug('No auth config found')
return None
def split_repo_name(repo_name): def split_repo_name(repo_name):
parts = repo_name.split('/', 1) parts = repo_name.split('/', 1)
if len(parts) == 1 or ( if len(parts) == 1 or (

View File

@ -36,7 +36,12 @@ class TaskTemplate(dict):
class ContainerSpec(dict): class ContainerSpec(dict):
def __init__(self, image, command=None, args=None, env=None, workdir=None, def __init__(self, image, command=None, args=None, env=None, workdir=None,
user=None, labels=None, mounts=None, stop_grace_period=None): user=None, labels=None, mounts=None, stop_grace_period=None):
from ..utils import split_command # FIXME: circular import
self['Image'] = image self['Image'] = image
if isinstance(command, six.string_types):
command = split_command(command)
self['Command'] = command self['Command'] = command
self['Args'] = args self['Args'] = args

View File

@ -666,6 +666,16 @@ Create a service, similar to the `docker service create` command. See the
Retrieve information about the current Swarm. Retrieve information about the current Swarm.
See the [Swarm documentation](swarm.md#clientinspect_swarm). See the [Swarm documentation](swarm.md#clientinspect_swarm).
## inspect_task
Retrieve information about a task.
**Params**:
* task (str): Task identifier
**Returns** (dict): Task information dictionary
## inspect_volume ## inspect_volume
Retrieve volume info by name. Retrieve volume info by name.
@ -1055,6 +1065,17 @@ Tag an image into a repository. Identical to the `docker tag` command.
**Returns** (bool): True if successful **Returns** (bool): True if successful
## tasks
Retrieve a list of tasks.
**Params**:
* filters (dict): A map of filters to process on the tasks list. Valid filters:
`id`, `name`, `service`, `node`, `label` and `desired-state`.
**Returns** (list): List of task dictionaries.
## top ## top
Display the running processes of a container. Display the running processes of a container.

View File

@ -1,7 +1,6 @@
import random import random
import docker import docker
# import pytest
from ..base import requires_api_version from ..base import requires_api_version
from .. import helpers from .. import helpers