Kaydet (Commit) e1ad3186 authored tarafından Joffrey F's avatar Joffrey F

Add create_plugin implementation

Signed-off-by: 's avatarJoffrey F <joffrey@docker.com>
üst cd05d8d5
No related merge requests found
...@@ -5,3 +5,4 @@ include README.rst ...@@ -5,3 +5,4 @@ include README.rst
include LICENSE include LICENSE
recursive-include tests *.py recursive-include tests *.py
recursive-include tests/unit/testdata * recursive-include tests/unit/testdata *
recursive-include tests/integration/testdata *
...@@ -26,21 +26,28 @@ class PluginApiMixin(object): ...@@ -26,21 +26,28 @@ class PluginApiMixin(object):
self._raise_for_status(res) self._raise_for_status(res)
return True return True
def create_plugin(self, name, rootfs, manifest): @utils.minimum_version('1.25')
def create_plugin(self, name, plugin_data_dir, gzip=False):
""" """
Create a new plugin. Create a new plugin.
Args: Args:
name (string): The name of the plugin. The ``:latest`` tag is name (string): The name of the plugin. The ``:latest`` tag is
optional, and is the default if omitted. optional, and is the default if omitted.
rootfs (string): Path to the plugin's ``rootfs`` plugin_data_dir (string): Path to the plugin data directory.
manifest (string): Path to the plugin's manifest file Plugin data directory must contain the ``config.json``
manifest file and the ``rootfs`` directory.
gzip (bool): Compress the context using gzip. Default: False
Returns: Returns:
``True`` if successful ``True`` if successful
""" """
# FIXME: Needs implementation url = self._url('/plugins/create')
raise NotImplementedError()
with utils.create_archive(root=plugin_data_dir, gzip=gzip) as archv:
res = self._post(url, params={'name': name}, data=archv)
self._raise_for_status(res)
return True
@utils.minimum_version('1.25') @utils.minimum_version('1.25')
def disable_plugin(self, name): def disable_plugin(self, name):
......
...@@ -100,20 +100,22 @@ class Plugin(Model): ...@@ -100,20 +100,22 @@ class Plugin(Model):
class PluginCollection(Collection): class PluginCollection(Collection):
model = Plugin model = Plugin
def create(self, name, rootfs, manifest): def create(self, name, plugin_data_dir, gzip=False):
""" """
Create a new plugin. Create a new plugin.
Args: Args:
name (string): The name of the plugin. The ``:latest`` tag is name (string): The name of the plugin. The ``:latest`` tag is
optional, and is the default if omitted. optional, and is the default if omitted.
rootfs (string): Path to the plugin's ``rootfs`` plugin_data_dir (string): Path to the plugin data directory.
manifest (string): Path to the plugin's manifest file Plugin data directory must contain the ``config.json``
manifest file and the ``rootfs`` directory.
gzip (bool): Compress the context using gzip. Default: False
Returns: Returns:
(:py:class:`Plugin`): The newly created plugin. (:py:class:`Plugin`): The newly created plugin.
""" """
self.client.api.create_plugin(name, rootfs, manifest) self.client.api.create_plugin(name, plugin_data_dir, gzip)
return self.get(name) return self.get(name)
def get(self, name): def get(self, name):
......
...@@ -6,7 +6,7 @@ from .utils import ( ...@@ -6,7 +6,7 @@ from .utils import (
create_host_config, parse_bytes, ping_registry, parse_env_file, version_lt, create_host_config, parse_bytes, ping_registry, parse_env_file, version_lt,
version_gte, decode_json_header, split_command, create_ipam_config, version_gte, decode_json_header, split_command, create_ipam_config,
create_ipam_pool, parse_devices, normalize_links, convert_service_networks, create_ipam_pool, parse_devices, normalize_links, convert_service_networks,
format_environment format_environment, create_archive
) )
from .decorators import check_resource, minimum_version, update_headers from .decorators import check_resource, minimum_version, update_headers
...@@ -80,16 +80,35 @@ def decode_json_header(header): ...@@ -80,16 +80,35 @@ def decode_json_header(header):
def tar(path, exclude=None, dockerfile=None, fileobj=None, gzip=False): def tar(path, exclude=None, dockerfile=None, fileobj=None, gzip=False):
if not fileobj:
fileobj = tempfile.NamedTemporaryFile()
t = tarfile.open(mode='w:gz' if gzip else 'w', fileobj=fileobj)
root = os.path.abspath(path) root = os.path.abspath(path)
exclude = exclude or [] exclude = exclude or []
for path in sorted(exclude_paths(root, exclude, dockerfile=dockerfile)): return create_archive(
i = t.gettarinfo(os.path.join(root, path), arcname=path) files=sorted(exclude_paths(root, exclude, dockerfile=dockerfile)),
root=root, fileobj=fileobj, gzip=gzip
)
def build_file_list(root):
files = []
for dirname, dirnames, fnames in os.walk(root):
for filename in fnames + dirnames:
longpath = os.path.join(dirname, filename)
files.append(
longpath.replace(root, '', 1).lstrip('/')
)
return files
def create_archive(root, files=None, fileobj=None, gzip=False):
if not fileobj:
fileobj = tempfile.NamedTemporaryFile()
t = tarfile.open(mode='w:gz' if gzip else 'w', fileobj=fileobj)
if files is None:
files = build_file_list(root)
for path in files:
i = t.gettarinfo(os.path.join(root, path), arcname=path)
if i is None: if i is None:
# This happens when we encounter a socket file. We can safely # This happens when we encounter a socket file. We can safely
# ignore it and proceed. # ignore it and proceed.
...@@ -102,13 +121,11 @@ def tar(path, exclude=None, dockerfile=None, fileobj=None, gzip=False): ...@@ -102,13 +121,11 @@ def tar(path, exclude=None, dockerfile=None, fileobj=None, gzip=False):
try: try:
# We open the file object in binary mode for Windows support. # We open the file object in binary mode for Windows support.
f = open(os.path.join(root, path), 'rb') with open(os.path.join(root, path), 'rb') as f:
t.addfile(i, f)
except IOError: except IOError:
# When we encounter a directory the file object is set to None. # When we encounter a directory the file object is set to None.
f = None t.addfile(i, None)
t.addfile(i, f)
t.close() t.close()
fileobj.seek(0) fileobj.seek(0)
return fileobj return fileobj
......
import os
import docker import docker
import pytest import pytest
from .base import BaseAPIIntegrationTest, TEST_API_VERSION from .base import BaseAPIIntegrationTest, TEST_API_VERSION
from ..helpers import requires_api_version
SSHFS = 'vieux/sshfs:latest' SSHFS = 'vieux/sshfs:latest'
@requires_api_version('1.25')
class PluginTest(BaseAPIIntegrationTest): class PluginTest(BaseAPIIntegrationTest):
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls):
...@@ -24,6 +28,12 @@ class PluginTest(BaseAPIIntegrationTest): ...@@ -24,6 +28,12 @@ class PluginTest(BaseAPIIntegrationTest):
except docker.errors.APIError: except docker.errors.APIError:
pass pass
for p in self.tmp_plugins:
try:
self.client.remove_plugin(p, force=True)
except docker.errors.APIError:
pass
def ensure_plugin_installed(self, plugin_name): def ensure_plugin_installed(self, plugin_name):
try: try:
return self.client.inspect_plugin(plugin_name) return self.client.inspect_plugin(plugin_name)
...@@ -112,3 +122,14 @@ class PluginTest(BaseAPIIntegrationTest): ...@@ -112,3 +122,14 @@ class PluginTest(BaseAPIIntegrationTest):
assert filter(lambda x: x['status'] == 'Download complete', logs) assert filter(lambda x: x['status'] == 'Download complete', logs)
assert self.client.inspect_plugin(SSHFS) assert self.client.inspect_plugin(SSHFS)
assert self.client.enable_plugin(SSHFS) assert self.client.enable_plugin(SSHFS)
def test_create_plugin(self):
plugin_data_dir = os.path.join(
os.path.dirname(__file__), 'testdata/dummy-plugin'
)
assert self.client.create_plugin(
'docker-sdk-py/dummy', plugin_data_dir
)
self.tmp_plugins.append('docker-sdk-py/dummy')
data = self.client.inspect_plugin('docker-sdk-py/dummy')
assert data['Config']['Entrypoint'] == ['/dummy']
...@@ -27,6 +27,7 @@ class BaseIntegrationTest(unittest.TestCase): ...@@ -27,6 +27,7 @@ class BaseIntegrationTest(unittest.TestCase):
self.tmp_folders = [] self.tmp_folders = []
self.tmp_volumes = [] self.tmp_volumes = []
self.tmp_networks = [] self.tmp_networks = []
self.tmp_plugins = []
def tearDown(self): def tearDown(self):
client = docker.from_env(version=TEST_API_VERSION) client = docker.from_env(version=TEST_API_VERSION)
......
{
"description": "Dummy test plugin for docker python SDK",
"documentation": "https://github.com/docker/docker-py",
"entrypoint": ["/dummy"],
"network": {
"type": "host"
},
"interface" : {
"types": ["docker.volumedriver/1.0"],
"socket": "dummy.sock"
},
"env": [
{
"name":"DEBUG",
"settable":["value"],
"value":"0"
}
]
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment