Skip to content

Commit

Permalink
Merge pull request docker#2506 from ulyssessouza/4.2.0-release
Browse files Browse the repository at this point in the history
4.2.0 release

Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
  • Loading branch information
ulyssessouza committed Feb 7, 2020
2 parents 6649587 + ab56784 commit eb6e6ca
Show file tree
Hide file tree
Showing 20 changed files with 718 additions and 38 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ matrix:
- env: TOXENV=flake8

install:
- pip install tox
- pip install tox==2.9.1
script:
- tox
2 changes: 1 addition & 1 deletion Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def buildImages = { ->

def getDockerVersions = { ->
def dockerVersions = ["17.06.2-ce"]
wrappedNode(label: "ubuntu && !zfs") {
wrappedNode(label: "ubuntu && !zfs && amd64") {
def result = sh(script: """docker run --rm \\
--entrypoint=python \\
${imageNamePy3} \\
Expand Down
3 changes: 2 additions & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
version: '{branch}-{build}'

install:
- "SET PATH=C:\\Python27-x64;C:\\Python27-x64\\Scripts;%PATH%"
- "SET PATH=C:\\Python37-x64;C:\\Python37-x64\\Scripts;%PATH%"
- "python --version"
- "python -m pip install --upgrade pip"
- "pip install tox==2.9.1"

# Build the binary after tests
Expand Down
3 changes: 3 additions & 0 deletions docker/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# flake8: noqa
from .api import APIClient
from .client import DockerClient, from_env
from .context import Context
from .context import ContextAPI
from .tls import TLSConfig
from .version import version, version_info

__version__ = version
Expand Down
12 changes: 12 additions & 0 deletions docker/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@
'memory', 'memswap', 'cpushares', 'cpusetcpus'
]

DEFAULT_HTTP_HOST = "127.0.0.1"
DEFAULT_UNIX_SOCKET = "http+unix:///var/run/docker.sock"
DEFAULT_NPIPE = 'npipe:////./pipe/docker_engine'

BYTE_UNITS = {
'b': 1,
'k': 1024,
'm': 1024 * 1024,
'g': 1024 * 1024 * 1024
}


INSECURE_REGISTRY_DEPRECATION_WARNING = \
'The `insecure_registry` argument to {} ' \
'is deprecated and non-functional. Please remove it.'
Expand Down
3 changes: 3 additions & 0 deletions docker/context/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# flake8: noqa
from .context import Context
from .api import ContextAPI
205 changes: 205 additions & 0 deletions docker/context/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
import json
import os

from docker import errors
from docker.context.config import get_meta_dir
from docker.context.config import METAFILE
from docker.context.config import get_current_context_name
from docker.context.config import write_context_name_to_docker_config
from docker.context import Context


class ContextAPI(object):
"""Context API.
Contains methods for context management:
create, list, remove, get, inspect.
"""
DEFAULT_CONTEXT = Context("default")

@classmethod
def create_context(
cls, name, orchestrator="swarm", host=None, tls_cfg=None,
default_namespace=None, skip_tls_verify=False):
"""Creates a new context.
Returns:
(Context): a Context object.
Raises:
:py:class:`docker.errors.MissingContextParameter`
If a context name is not provided.
:py:class:`docker.errors.ContextAlreadyExists`
If a context with the name already exists.
:py:class:`docker.errors.ContextException`
If name is default.
Example:
>>> from docker.context import ContextAPI
>>> ctx = ContextAPI.create_context(name='test')
>>> print(ctx.Metadata)
{
"Name": "test",
"Metadata": {
"StackOrchestrator": "swarm"
},
"Endpoints": {
"docker": {
"Host": "unix:///var/run/docker.sock",
"SkipTLSVerify": false
}
}
}
"""
if not name:
raise errors.MissingContextParameter("name")
if name == "default":
raise errors.ContextException(
'"default" is a reserved context name')
ctx = Context.load_context(name)
if ctx:
raise errors.ContextAlreadyExists(name)
endpoint = "docker" if orchestrator == "swarm" else orchestrator
ctx = Context(name, orchestrator)
ctx.set_endpoint(
endpoint, host, tls_cfg,
skip_tls_verify=skip_tls_verify,
def_namespace=default_namespace)
ctx.save()
return ctx

@classmethod
def get_context(cls, name=None):
"""Retrieves a context object.
Args:
name (str): The name of the context
Example:
>>> from docker.context import ContextAPI
>>> ctx = ContextAPI.get_context(name='test')
>>> print(ctx.Metadata)
{
"Name": "test",
"Metadata": {
"StackOrchestrator": "swarm"
},
"Endpoints": {
"docker": {
"Host": "unix:///var/run/docker.sock",
"SkipTLSVerify": false
}
}
}
"""
if not name:
name = get_current_context_name()
if name == "default":
return cls.DEFAULT_CONTEXT
return Context.load_context(name)

@classmethod
def contexts(cls):
"""Context list.
Returns:
(Context): List of context objects.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
names = []
for dirname, dirnames, fnames in os.walk(get_meta_dir()):
for filename in fnames + dirnames:
if filename == METAFILE:
try:
data = json.load(
open(os.path.join(dirname, filename), "r"))
names.append(data["Name"])
except Exception as e:
raise errors.ContextException(
"Failed to load metafile {}: {}".format(
filename, e))

contexts = [cls.DEFAULT_CONTEXT]
for name in names:
contexts.append(Context.load_context(name))
return contexts

@classmethod
def get_current_context(cls):
"""Get current context.
Returns:
(Context): current context object.
"""
return cls.get_context()

@classmethod
def set_current_context(cls, name="default"):
ctx = cls.get_context(name)
if not ctx:
raise errors.ContextNotFound(name)

err = write_context_name_to_docker_config(name)
if err:
raise errors.ContextException(
'Failed to set current context: {}'.format(err))

@classmethod
def remove_context(cls, name):
"""Remove a context. Similar to the ``docker context rm`` command.
Args:
name (str): The name of the context
Raises:
:py:class:`docker.errors.MissingContextParameter`
If a context name is not provided.
:py:class:`docker.errors.ContextNotFound`
If a context with the name does not exist.
:py:class:`docker.errors.ContextException`
If name is default.
Example:
>>> from docker.context import ContextAPI
>>> ContextAPI.remove_context(name='test')
>>>
"""
if not name:
raise errors.MissingContextParameter("name")
if name == "default":
raise errors.ContextException(
'context "default" cannot be removed')
ctx = Context.load_context(name)
if not ctx:
raise errors.ContextNotFound(name)
if name == get_current_context_name():
write_context_name_to_docker_config(None)
ctx.remove()

@classmethod
def inspect_context(cls, name="default"):
"""Remove a context. Similar to the ``docker context inspect`` command.
Args:
name (str): The name of the context
Raises:
:py:class:`docker.errors.MissingContextParameter`
If a context name is not provided.
:py:class:`docker.errors.ContextNotFound`
If a context with the name does not exist.
Example:
>>> from docker.context import ContextAPI
>>> ContextAPI.remove_context(name='test')
>>>
"""
if not name:
raise errors.MissingContextParameter("name")
if name == "default":
return cls.DEFAULT_CONTEXT()
ctx = Context.load_context(name)
if not ctx:
raise errors.ContextNotFound(name)

return ctx()
81 changes: 81 additions & 0 deletions docker/context/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import os
import json
import hashlib

from docker import utils
from docker.constants import IS_WINDOWS_PLATFORM
from docker.constants import DEFAULT_UNIX_SOCKET
from docker.utils.config import find_config_file

METAFILE = "meta.json"


def get_current_context_name():
name = "default"
docker_cfg_path = find_config_file()
if docker_cfg_path:
try:
with open(docker_cfg_path, "r") as f:
name = json.load(f).get("currentContext", "default")
except Exception:
return "default"
return name


def write_context_name_to_docker_config(name=None):
if name == 'default':
name = None
docker_cfg_path = find_config_file()
config = {}
if docker_cfg_path:
try:
with open(docker_cfg_path, "r") as f:
config = json.load(f)
except Exception as e:
return e
current_context = config.get("currentContext", None)
if current_context and not name:
del config["currentContext"]
elif name:
config["currentContext"] = name
else:
return
try:
with open(docker_cfg_path, "w") as f:
json.dump(config, f, indent=4)
except Exception as e:
return e


def get_context_id(name):
return hashlib.sha256(name.encode('utf-8')).hexdigest()


def get_context_dir():
return os.path.join(os.path.dirname(find_config_file() or ""), "contexts")


def get_meta_dir(name=None):
meta_dir = os.path.join(get_context_dir(), "meta")
if name:
return os.path.join(meta_dir, get_context_id(name))
return meta_dir


def get_meta_file(name):
return os.path.join(get_meta_dir(name), METAFILE)


def get_tls_dir(name=None, endpoint=""):
context_dir = get_context_dir()
if name:
return os.path.join(context_dir, "tls", get_context_id(name), endpoint)
return os.path.join(context_dir, "tls")


def get_context_host(path=None):
host = utils.parse_host(path, IS_WINDOWS_PLATFORM)
if host == DEFAULT_UNIX_SOCKET:
# remove http+ from default docker socket url
return host.strip("http+")
return host

0 comments on commit eb6e6ca

Please sign in to comment.