diff --git a/docs/api/v1/docker.rst b/docs/api/v1/docker.rst deleted file mode 100644 index 2e700cc8..00000000 --- a/docs/api/v1/docker.rst +++ /dev/null @@ -1,8 +0,0 @@ -Docker ---------------------- - -.. toctree:: - :glob: - :maxdepth: 2 - - docker/* diff --git a/docs/api/v1/docker/dockerimages.rst b/docs/api/v1/docker/dockerimages.rst deleted file mode 100644 index d282af92..00000000 --- a/docs/api/v1/docker/dockerimages.rst +++ /dev/null @@ -1,13 +0,0 @@ -/v1/docker/images ----------------------------------------------------------------------------------------------------------------------- - -.. contents:: - -GET /v1/docker/images -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Get all available Docker images - -Response status codes -********************** -- **200**: Success - diff --git a/docs/api/v1/docker/projectsprojectiddockerimages.rst b/docs/api/v1/docker/projectsprojectiddockerimages.rst deleted file mode 100644 index 01f41cc4..00000000 --- a/docs/api/v1/docker/projectsprojectiddockerimages.rst +++ /dev/null @@ -1,49 +0,0 @@ -/v1/projects/{project_id}/docker/images ----------------------------------------------------------------------------------------------------------------------- - -.. contents:: - -POST /v1/projects/**{project_id}**/docker/images -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Create a new Docker container - -Parameters -********** -- **project_id**: UUID for the project - -Response status codes -********************** -- **400**: Invalid request -- **201**: Instance created -- **409**: Conflict - -Input -******* -.. raw:: html - - - - - - - - - - -
Name Mandatory Type Description
adapter_type string Docker adapter type
adapters integer number of adapters
console string console name
imagename string Docker image name
name string Docker container name
startcmd string Docker CMD entry
vm_id Docker VM instance identifier
- -Output -******* -.. raw:: html - - - - - - - - - - -
Name Mandatory Type Description
adapter_type string Docker adapter type
adapters integer number of adapters
cid string Docker container ID
image string Docker image name
name string Docker container name
project_id string Project UUID
vm_id string Docker container instance UUID
- diff --git a/docs/api/v1/docker/projectsprojectiddockerimagesid.rst b/docs/api/v1/docker/projectsprojectiddockerimagesid.rst deleted file mode 100644 index 6a9e006d..00000000 --- a/docs/api/v1/docker/projectsprojectiddockerimagesid.rst +++ /dev/null @@ -1,20 +0,0 @@ -/v1/projects/{project_id}/docker/images/{id} ----------------------------------------------------------------------------------------------------------------------- - -.. contents:: - -DELETE /v1/projects/**{project_id}**/docker/images/**{id}** -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Delete a Docker container - -Parameters -********** -- **id**: ID for the container -- **project_id**: UUID for the project - -Response status codes -********************** -- **400**: Invalid request -- **404**: Instance doesn't exist -- **204**: Instance deleted - diff --git a/docs/api/v1/docker/projectsprojectiddockerimagesidadaptersadapternumberdportsportnumberdnio.rst b/docs/api/v1/docker/projectsprojectiddockerimagesidadaptersadapternumberdportsportnumberdnio.rst deleted file mode 100644 index e5724d50..00000000 --- a/docs/api/v1/docker/projectsprojectiddockerimagesidadaptersadapternumberdportsportnumberdnio.rst +++ /dev/null @@ -1,40 +0,0 @@ -/v1/projects/{project_id}/docker/images/{id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio ----------------------------------------------------------------------------------------------------------------------- - -.. contents:: - -POST /v1/projects/**{project_id}**/docker/images/**{id}**/adapters/**{adapter_number:\d+}**/ports/**{port_number:\d+}**/nio -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Add a NIO to a Docker container - -Parameters -********** -- **id**: ID of the container -- **adapter_number**: Adapter where the nio should be added -- **project_id**: UUID for the project -- **port_number**: Port on the adapter - -Response status codes -********************** -- **400**: Invalid request -- **201**: NIO created -- **404**: Instance doesn't exist - - -DELETE /v1/projects/**{project_id}**/docker/images/**{id}**/adapters/**{adapter_number:\d+}**/ports/**{port_number:\d+}**/nio -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Remove a NIO from a Docker container - -Parameters -********** -- **id**: ID of the container -- **adapter_number**: Adapter where the nio should be added -- **project_id**: UUID for the project -- **port_number**: Port on the adapter - -Response status codes -********************** -- **400**: Invalid request -- **404**: Instance doesn't exist -- **204**: NIO deleted - diff --git a/docs/api/v1/docker/projectsprojectiddockerimagesidreload.rst b/docs/api/v1/docker/projectsprojectiddockerimagesidreload.rst deleted file mode 100644 index df8104d0..00000000 --- a/docs/api/v1/docker/projectsprojectiddockerimagesidreload.rst +++ /dev/null @@ -1,50 +0,0 @@ -/v1/projects/{project_id}/docker/images/{id}/reload ----------------------------------------------------------------------------------------------------------------------- - -.. contents:: - -POST /v1/projects/**{project_id}**/docker/images/**{id}**/reload -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Restart a Docker container - -Parameters -********** -- **id**: ID of the container -- **project_id**: UUID of the project - -Response status codes -********************** -- **400**: Invalid request -- **404**: Instance doesn't exist -- **204**: Instance restarted - -Input -******* -.. raw:: html - - - - - - - - - - -
Name Mandatory Type Description
adapter_type string Docker adapter type
adapters integer number of adapters
console string console name
imagename string Docker image name
name string Docker container name
startcmd string Docker CMD entry
vm_id Docker VM instance identifier
- -Output -******* -.. raw:: html - - - - - - - - - - -
Name Mandatory Type Description
adapter_type string Docker adapter type
adapters integer number of adapters
cid string Docker container ID
image string Docker image name
name string Docker container name
project_id string Project UUID
vm_id string Docker container instance UUID
- diff --git a/docs/api/v1/docker/projectsprojectiddockerimagesidstart.rst b/docs/api/v1/docker/projectsprojectiddockerimagesidstart.rst deleted file mode 100644 index 49fb5e28..00000000 --- a/docs/api/v1/docker/projectsprojectiddockerimagesidstart.rst +++ /dev/null @@ -1,50 +0,0 @@ -/v1/projects/{project_id}/docker/images/{id}/start ----------------------------------------------------------------------------------------------------------------------- - -.. contents:: - -POST /v1/projects/**{project_id}**/docker/images/**{id}**/start -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Start a Docker container - -Parameters -********** -- **id**: ID of the container -- **project_id**: UUID of the project - -Response status codes -********************** -- **400**: Invalid request -- **404**: Instance doesn't exist -- **204**: Instance started - -Input -******* -.. raw:: html - - - - - - - - - - -
Name Mandatory Type Description
adapter_type string Docker adapter type
adapters integer number of adapters
console string console name
imagename string Docker image name
name string Docker container name
startcmd string Docker CMD entry
vm_id Docker VM instance identifier
- -Output -******* -.. raw:: html - - - - - - - - - - -
Name Mandatory Type Description
adapter_type string Docker adapter type
adapters integer number of adapters
cid string Docker container ID
image string Docker image name
name string Docker container name
project_id string Project UUID
vm_id string Docker container instance UUID
- diff --git a/docs/api/v1/docker/projectsprojectiddockerimagesidstop.rst b/docs/api/v1/docker/projectsprojectiddockerimagesidstop.rst deleted file mode 100644 index 797eb66c..00000000 --- a/docs/api/v1/docker/projectsprojectiddockerimagesidstop.rst +++ /dev/null @@ -1,50 +0,0 @@ -/v1/projects/{project_id}/docker/images/{id}/stop ----------------------------------------------------------------------------------------------------------------------- - -.. contents:: - -POST /v1/projects/**{project_id}**/docker/images/**{id}**/stop -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Stop a Docker container - -Parameters -********** -- **id**: ID of the container -- **project_id**: UUID of the project - -Response status codes -********************** -- **400**: Invalid request -- **404**: Instance doesn't exist -- **204**: Instance stopped - -Input -******* -.. raw:: html - - - - - - - - - - -
Name Mandatory Type Description
adapter_type string Docker adapter type
adapters integer number of adapters
console string console name
imagename string Docker image name
name string Docker container name
startcmd string Docker CMD entry
vm_id Docker VM instance identifier
- -Output -******* -.. raw:: html - - - - - - - - - - -
Name Mandatory Type Description
adapter_type string Docker adapter type
adapters integer number of adapters
cid string Docker container ID
image string Docker image name
name string Docker container name
project_id string Project UUID
vm_id string Docker container instance UUID
- diff --git a/docs/api/v1/docker/projectsprojectiddockerimagesidsuspend.rst b/docs/api/v1/docker/projectsprojectiddockerimagesidsuspend.rst deleted file mode 100644 index 11297147..00000000 --- a/docs/api/v1/docker/projectsprojectiddockerimagesidsuspend.rst +++ /dev/null @@ -1,50 +0,0 @@ -/v1/projects/{project_id}/docker/images/{id}/suspend ----------------------------------------------------------------------------------------------------------------------- - -.. contents:: - -POST /v1/projects/**{project_id}**/docker/images/**{id}**/suspend -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Pause a Docker container - -Parameters -********** -- **id**: ID of the container -- **project_id**: UUID of the project - -Response status codes -********************** -- **400**: Invalid request -- **404**: Instance doesn't exist -- **204**: Instance paused - -Input -******* -.. raw:: html - - - - - - - - - - -
Name Mandatory Type Description
adapter_type string Docker adapter type
adapters integer number of adapters
console string console name
imagename string Docker image name
name string Docker container name
startcmd string Docker CMD entry
vm_id Docker VM instance identifier
- -Output -******* -.. raw:: html - - - - - - - - - - -
Name Mandatory Type Description
adapter_type string Docker adapter type
adapters integer number of adapters
cid string Docker container ID
image string Docker image name
name string Docker container name
project_id string Project UUID
vm_id string Docker container instance UUID
- diff --git a/gns3server/handlers/__init__.py b/gns3server/handlers/__init__.py index d2fb9b5f..68297c25 100644 --- a/gns3server/handlers/__init__.py +++ b/gns3server/handlers/__init__.py @@ -24,7 +24,6 @@ from gns3server.handlers.api.dynamips_device_handler import DynamipsDeviceHandle from gns3server.handlers.api.dynamips_vm_handler import DynamipsVMHandler from gns3server.handlers.api.qemu_handler import QEMUHandler from gns3server.handlers.api.virtualbox_handler import VirtualBoxHandler -from gns3server.handlers.api.docker_handler import DockerHandler from gns3server.handlers.api.vpcs_handler import VPCSHandler from gns3server.handlers.api.vmware_handler import VMwareHandler from gns3server.handlers.api.config_handler import ConfigHandler diff --git a/gns3server/handlers/api/docker_handler.py b/gns3server/handlers/api/docker_handler.py deleted file mode 100644 index 0f015054..00000000 --- a/gns3server/handlers/api/docker_handler.py +++ /dev/null @@ -1,247 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2015 GNS3 Technologies Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from aiohttp.web import HTTPConflict - -from ...web.route import Route -from ...modules.docker import Docker - -from ...schemas.docker import ( - DOCKER_CREATE_SCHEMA, DOCKER_UPDATE_SCHEMA, DOCKER_CAPTURE_SCHEMA, - DOCKER_OBJECT_SCHEMA -) -from ...schemas.nio import NIO_SCHEMA - - -class DockerHandler: - """API entry points for Docker.""" - - @classmethod - @Route.get( - r"/docker/images", - status_codes={ - 200: "Success", - }, - description="Get all available Docker images") - def show(request, response): - docker_manager = Docker.instance() - images = yield from docker_manager.list_images() - response.json(images) - - @classmethod - @Route.post( - r"/projects/{project_id}/docker/images", - parameters={ - "project_id": "UUID for the project" - }, - status_codes={ - 201: "Instance created", - 400: "Invalid request", - 409: "Conflict" - }, - description="Create a new Docker container", - input=DOCKER_CREATE_SCHEMA, - output=DOCKER_OBJECT_SCHEMA) - def create(request, response): - docker_manager = Docker.instance() - container = yield from docker_manager.create_vm( - request.json.pop("name"), - request.match_info["project_id"], - request.json.get("id"), - image=request.json.pop("imagename"), - startcmd=request.json.get("startcmd") - ) - # FIXME: DO WE NEED THIS? - for name, value in request.json.items(): - if name != "_vm_id": - if hasattr(container, name) and getattr(container, name) != value: - setattr(container, name, value) - - response.set_status(201) - response.json(container) - - @classmethod - @Route.post( - r"/projects/{project_id}/docker/images/{id}/start", - parameters={ - "project_id": "UUID of the project", - "id": "ID of the container" - }, - status_codes={ - 204: "Instance started", - 400: "Invalid request", - 404: "Instance doesn't exist" - }, - description="Start a Docker container", - input=DOCKER_CREATE_SCHEMA, - output=DOCKER_OBJECT_SCHEMA) - def start(request, response): - docker_manager = Docker.instance() - container = docker_manager.get_container( - request.match_info["id"], - project_id=request.match_info["project_id"]) - yield from container.start() - response.set_status(204) - - @classmethod - @Route.post( - r"/projects/{project_id}/docker/images/{id}/stop", - parameters={ - "project_id": "UUID of the project", - "id": "ID of the container" - }, - status_codes={ - 204: "Instance stopped", - 400: "Invalid request", - 404: "Instance doesn't exist" - }, - description="Stop a Docker container", - input=DOCKER_CREATE_SCHEMA, - output=DOCKER_OBJECT_SCHEMA) - def stop(request, response): - docker_manager = Docker.instance() - container = docker_manager.get_container( - request.match_info["id"], - project_id=request.match_info["project_id"]) - yield from container.stop() - response.set_status(204) - - @classmethod - @Route.post( - r"/projects/{project_id}/docker/images/{id}/reload", - parameters={ - "project_id": "UUID of the project", - "id": "ID of the container" - }, - status_codes={ - 204: "Instance restarted", - 400: "Invalid request", - 404: "Instance doesn't exist" - }, - description="Restart a Docker container", - input=DOCKER_CREATE_SCHEMA, - output=DOCKER_OBJECT_SCHEMA) - def reload(request, response): - docker_manager = Docker.instance() - container = docker_manager.get_container( - request.match_info["id"], - project_id=request.match_info["project_id"]) - yield from container.restart() - response.set_status(204) - - @classmethod - @Route.delete( - r"/projects/{project_id}/docker/images/{id}", - parameters={ - "id": "ID for the container", - "project_id": "UUID for the project" - }, - status_codes={ - 204: "Instance deleted", - 400: "Invalid request", - 404: "Instance doesn't exist" - }, - description="Delete a Docker container") - def delete(request, response): - docker_manager = Docker.instance() - container = docker_manager.get_container( - request.match_info["id"], - project_id=request.match_info["project_id"]) - yield from container.remove() - response.set_status(204) - - @classmethod - @Route.post( - r"/projects/{project_id}/docker/images/{id}/suspend", - parameters={ - "project_id": "UUID of the project", - "id": "ID of the container" - }, - status_codes={ - 204: "Instance paused", - 400: "Invalid request", - 404: "Instance doesn't exist" - }, - description="Pause a Docker container", - input=DOCKER_CREATE_SCHEMA, - output=DOCKER_OBJECT_SCHEMA) - def suspend(request, response): - docker_manager = Docker.instance() - container = docker_manager.get_container( - request.match_info["id"], - project_id=request.match_info["project_id"]) - yield from container.pause() - response.set_status(204) - - @Route.post( - r"/projects/{project_id}/docker/images/{id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio", - parameters={ - "project_id": "UUID for the project", - "id": "ID of the container", - "adapter_number": "Adapter where the nio should be added", - "port_number": "Port on the adapter" - }, - status_codes={ - 201: "NIO created", - 400: "Invalid request", - 404: "Instance doesn't exist" - }, - description="Add a NIO to a Docker container", - input=NIO_SCHEMA, - output=NIO_SCHEMA) - def create_nio(request, response): - docker_manager = Docker.instance() - container = docker_manager.get_container( - request.match_info["id"], - project_id=request.match_info["project_id"]) - nio_type = request.json["type"] - if nio_type not in ("nio_udp"): - raise HTTPConflict( - text="NIO of type {} is not supported".format(nio_type)) - nio = docker_manager.create_nio( - int(request.match_info["adapter_number"]), request.json) - adapter = container._ethernet_adapters[ - int(request.match_info["adapter_number"]) - ] - container.adapter_add_nio_binding( - int(request.match_info["adapter_number"]), nio) - response.set_status(201) - response.json(nio) - - @classmethod - @Route.delete( - r"/projects/{project_id}/docker/images/{id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio", - parameters={ - "project_id": "UUID for the project", - "id": "ID of the container", - "adapter_number": "Adapter where the nio should be added", - "port_number": "Port on the adapter" - }, - status_codes={ - 204: "NIO deleted", - 400: "Invalid request", - 404: "Instance doesn't exist" - }, - description="Remove a NIO from a Docker container") - def delete_nio(request, response): - docker_manager = Docker.instance() - container = docker_manager.get_container( - request.match_info["id"], - project_id=request.match_info["project_id"]) - yield from container.adapter_remove_nio_binding( - int(request.match_info["adapter_number"])) - response.set_status(204) diff --git a/gns3server/modules/docker/__init__.py b/gns3server/modules/docker/__init__.py deleted file mode 100644 index c20a4efb..00000000 --- a/gns3server/modules/docker/__init__.py +++ /dev/null @@ -1,119 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2015 GNS3 Technologies Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" -Docker server module. -""" - -import asyncio -import logging -import aiohttp -import docker -from requests.exceptions import ConnectionError - -log = logging.getLogger(__name__) - -from ..base_manager import BaseManager -from ..project_manager import ProjectManager -from .docker_vm import Container -from .docker_error import DockerError - - -class Docker(BaseManager): - - _VM_CLASS = Container - - def __init__(self): - super().__init__() - # FIXME: make configurable and start docker before trying - self._server_url = 'unix://var/run/docker.sock' - self._client = docker.Client(base_url=self._server_url) - self._execute_lock = asyncio.Lock() - - @property - def server_url(self): - """Returns the Docker server url. - - :returns: url - :rtype: string - """ - return self._server_url - - @server_url.setter - def server_url(self, value): - self._server_url = value - self._client = docker.Client(base_url=value) - - @asyncio.coroutine - def execute(self, command, kwargs, timeout=60): - command = getattr(self._client, command) - log.debug("Executing Docker with command: {}".format(command)) - try: - result = command(**kwargs) - except Exception as error: - raise DockerError("Docker has returned an error: {}".format(error)) - return result - - @asyncio.coroutine - def list_images(self): - """Gets Docker image list. - - :returns: list of dicts - :rtype: list - """ - images = [] - try: - for image in self._client.images(): - for tag in image['RepoTags']: - images.append({'imagename': tag}) - return images - except ConnectionError as error: - raise DockerError( - """Docker couldn't list images and returned an error: {} -Is the Docker service running?""".format(error)) - - @asyncio.coroutine - def list_containers(self): - """Gets Docker container list. - - :returns: list of dicts - :rtype: list - """ - return self._client.containers() - - def get_container(self, cid, project_id=None): - """Returns a Docker container. - - :param id: Docker container identifier - :param project_id: Project identifier - - :returns: Docker container - """ - if project_id: - project = ProjectManager.instance().get_project(project_id) - - if cid not in self._vms: - raise aiohttp.web.HTTPNotFound( - text="Docker container with ID {} doesn't exist".format(cid)) - - container = self._vms[cid] - if project_id: - if container.project.id != project.id: - raise aiohttp.web.HTTPNotFound( - text="Project ID {} doesn't belong to container {}".format( - project_id, container.name)) - return container diff --git a/gns3server/modules/docker/docker_error.py b/gns3server/modules/docker/docker_error.py deleted file mode 100644 index 2e03ace5..00000000 --- a/gns3server/modules/docker/docker_error.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2015 GNS3 Technologies Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" -Custom exceptions for the Docker module. -""" - -from ..vm_error import VMError - - -class DockerError(VMError): - pass diff --git a/gns3server/modules/docker/docker_vm.py b/gns3server/modules/docker/docker_vm.py deleted file mode 100644 index 517e8126..00000000 --- a/gns3server/modules/docker/docker_vm.py +++ /dev/null @@ -1,403 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2015 GNS3 Technologies Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" -Docker container instance. -""" - -import asyncio -import shutil -import psutil - -from docker.utils import create_host_config -from gns3server.ubridge.hypervisor import Hypervisor -from pkg_resources import parse_version -from .docker_error import DockerError -from ..base_vm import BaseVM -from ..adapters.ethernet_adapter import EthernetAdapter -from ..nios.nio_udp import NIOUDP - -import logging -log = logging.getLogger(__name__) - - -class Container(BaseVM): - """Docker container implementation. - - :param name: Docker container name - :param vm_id: Docker VM identifier - :param project: Project instance - :param manager: Manager instance - :param image: Docker image - """ - - def __init__(self, name, vm_id, project, manager, image, startcmd=None): - self._name = name - self._id = vm_id - self._project = project - self._manager = manager - self._image = image - self._startcmd = startcmd - self._veths = [] - self._ethernet_adapters = [] - self._ubridge_hypervisor = None - self._temporary_directory = None - self._hw_virtualization = False - - log.debug( - "{module}: {name} [{image}] initialized.".format( - module=self.manager.module_name, - name=self.name, - image=self._image)) - - def __json__(self): - return { - "name": self._name, - "vm_id": self._id, - "cid": self._cid, - "project_id": self._project.id, - "image": self._image, - } - - @property - def veths(self): - """Returns Docker host veth interfaces.""" - return self._veths - - @asyncio.coroutine - def _get_container_state(self): - """Returns the container state (e.g. running, paused etc.) - - :returns: state - :rtype: str - """ - try: - result = yield from self.manager.execute( - "inspect_container", {"container": self._cid}) - result_dict = {state.lower(): value for state, value in result["State"].items()} - for state, value in result_dict.items(): - if value is True: - # a container can be both paused and running - if state == "paused": - return "paused" - if state == "running": - if "paused" in result_dict and result_dict["paused"] is True: - return "paused" - return state.lower() - return 'exited' - except Exception as err: - raise DockerError("Could not get container state for {0}: ".format( - self._name), str(err)) - - @asyncio.coroutine - def create(self): - """Creates the Docker container.""" - params = { - "name": self._name, - "image": self._image, - "network_disabled": True, - "host_config": create_host_config( - privileged=True, cap_add=['ALL']) - } - if self._startcmd: - params.update({'command': self._startcmd}) - - result = yield from self.manager.execute("create_container", params) - self._cid = result['Id'] - log.info("Docker container '{name}' [{id}] created".format( - name=self._name, id=self._id)) - return True - - @property - def ubridge_path(self): - """Returns the uBridge executable path. - - :returns: path to uBridge - """ - path = self._manager.config.get_section_config("Server").get( - "ubridge_path", "ubridge") - if path == "ubridge": - path = shutil.which("ubridge") - return path - - @asyncio.coroutine - def _start_ubridge(self): - """Starts uBridge (handles connections to and from this Docker VM).""" - server_config = self._manager.config.get_section_config("Server") - server_host = server_config.get("host") - self._ubridge_hypervisor = Hypervisor( - self._project, self.ubridge_path, self.working_dir, server_host) - - log.info("Starting new uBridge hypervisor {}:{}".format( - self._ubridge_hypervisor.host, self._ubridge_hypervisor.port)) - yield from self._ubridge_hypervisor.start() - log.info("Hypervisor {}:{} has successfully started".format( - self._ubridge_hypervisor.host, self._ubridge_hypervisor.port)) - yield from self._ubridge_hypervisor.connect() - if parse_version( - self._ubridge_hypervisor.version) < parse_version('0.9.1'): - raise DockerError( - "uBridge version must be >= 0.9.1, detected version is {}".format( - self._ubridge_hypervisor.version)) - - @asyncio.coroutine - def start(self): - """Starts this Docker container.""" - - state = yield from self._get_container_state() - if state == "paused": - yield from self.unpause() - else: - result = yield from self.manager.execute( - "start", {"container": self._cid}) - - yield from self._start_ubridge() - for adapter_number in range(0, self.adapters): - nio = self._ethernet_adapters[adapter_number].get_nio(0) - if nio: - yield from self._add_ubridge_connection(nio, adapter_number) - - log.info("Docker container '{name}' [{image}] started".format( - name=self._name, image=self._image)) - - def is_running(self): - """Checks if the container is running. - - :returns: True or False - :rtype: bool - """ - state = yield from self._get_container_state() - if state == "running": - return True - return False - - @asyncio.coroutine - def restart(self): - """Restarts this Docker container.""" - result = yield from self.manager.execute( - "restart", {"container": self._cid}) - log.info("Docker container '{name}' [{image}] restarted".format( - name=self._name, image=self._image)) - - @asyncio.coroutine - def stop(self): - """Stops this Docker container.""" - - if self._ubridge_hypervisor and self._ubridge_hypervisor.is_running(): - yield from self._ubridge_hypervisor.stop() - - state = yield from self._get_container_state() - if state == "paused": - yield from self.unpause() - result = yield from self.manager.execute( - "kill", {"container": self._cid}) - log.info("Docker container '{name}' [{image}] stopped".format( - name=self._name, image=self._image)) - - @asyncio.coroutine - def pause(self): - """Pauses this Docker container.""" - result = yield from self.manager.execute( - "pause", {"container": self._cid}) - log.info("Docker container '{name}' [{image}] paused".format( - name=self._name, image=self._image)) - - @asyncio.coroutine - def unpause(self): - """Unpauses this Docker container.""" - result = yield from self.manager.execute( - "unpause", {"container": self._cid}) - state = yield from self._get_container_state() - log.info("Docker container '{name}' [{image}] unpaused".format( - name=self._name, image=self._image)) - - @asyncio.coroutine - def remove(self): - """Removes this Docker container.""" - state = yield from self._get_container_state() - if state == "paused": - yield from self.unpause() - if state == "running": - yield from self.stop() - result = yield from self.manager.execute( - "remove_container", {"container": self._cid, "force": True}) - log.info("Docker container '{name}' [{image}] removed".format( - name=self._name, image=self._image)) - - @asyncio.coroutine - def close(self): - """Closes this Docker container.""" - log.debug("Docker container '{name}' [{id}] is closing".format( - name=self.name, id=self._cid)) - for adapter in self._ethernet_adapters.values(): - if adapter is not None: - for nio in adapter.ports.values(): - if nio and isinstance(nio, NIOUDP): - self.manager.port_manager.release_udp_port( - nio.lport, self._project) - - yield from self.remove() - - log.info("Docker container '{name}' [{id}] closed".format( - name=self.name, id=self._cid)) - self._closed = True - - def _add_ubridge_connection(self, nio, adapter_number): - """ - Creates a connection in uBridge. - - :param nio: NIO instance - :param adapter_number: adapter number - """ - try: - adapter = self._ethernet_adapters[adapter_number] - except IndexError: - raise DockerError( - "Adapter {adapter_number} doesn't exist on Docker container '{name}'".format( - name=self.name, adapter_number=adapter_number)) - - if nio and isinstance(nio, NIOUDP): - for index in range(128): - if "gns3-veth{}ext".format(index) not in psutil.net_if_addrs(): - adapter.ifc = "eth{}".format(str(index)) - adapter.host_ifc = "gns3-veth{}ext".format(str(index)) - adapter.guest_ifc = "gns3-veth{}int".format(str(index)) - break - if not hasattr(adapter, "ifc"): - raise DockerError( - "Adapter {adapter_number} couldn't allocate interface on Docker container '{name}'".format( - name=self.name, adapter_number=adapter_number)) - - yield from self._ubridge_hypervisor.send( - 'docker create_veth {hostif} {guestif}'.format( - guestif=adapter.guest_ifc, hostif=adapter.host_ifc)) - self._veths.append(adapter.host_ifc) - - namespace = yield from self.get_namespace() - yield from self._ubridge_hypervisor.send( - 'docker move_to_ns {ifc} {ns}'.format( - ifc=adapter.guest_ifc, ns=namespace)) - - yield from self._ubridge_hypervisor.send( - 'bridge create bridge{}'.format(adapter_number)) - yield from self._ubridge_hypervisor.send( - 'bridge add_nio_linux_raw bridge{adapter} {ifc}'.format( - ifc=adapter.host_ifc, adapter=adapter_number)) - - if isinstance(nio, NIOUDP): - yield from self._ubridge_hypervisor.send( - 'bridge add_nio_udp bridge{adapter} {lport} {rhost} {rport}'.format( - adapter=adapter_number, lport=nio.lport, rhost=nio.rhost, - rport=nio.rport)) - - if nio.capturing: - yield from self._ubridge_hypervisor.send( - 'bridge start_capture bridge{adapter} "{pcap_file}"'.format( - adapter=adapter_number, pcap_file=nio.pcap_output_file)) - - yield from self._ubridge_hypervisor.send( - 'bridge start bridge{adapter}'.format(adapter=adapter_number)) - - def _delete_ubridge_connection(self, adapter_number): - """Deletes a connection in uBridge. - - :param adapter_number: adapter number - """ - yield from self._ubridge_hypervisor.send("bridge delete bridge{name}".format( - name=adapter_number)) - - adapter = self._ethernet_adapters[adapter_number] - yield from self._ubridge_hypervisor.send("docker delete_veth {name}".format( - name=adapter.host_ifc)) - - def adapter_add_nio_binding(self, adapter_number, nio): - """Adds an adapter NIO binding. - - :param adapter_number: adapter number - :param nio: NIO instance to add to the slot/port - """ - try: - adapter = self._ethernet_adapters[adapter_number] - except IndexError: - raise DockerError( - "Adapter {adapter_number} doesn't exist on Docker container '{name}'".format( - name=self.name, adapter_number=adapter_number)) - - adapter.add_nio(0, nio) - log.info( - "Docker container '{name}' [{id}]: {nio} added to adapter {adapter_number}".format( - name=self.name, - id=self._id, - nio=nio, - adapter_number=adapter_number)) - - def adapter_remove_nio_binding(self, adapter_number): - """ - Removes an adapter NIO binding. - - :param adapter_number: adapter number - - :returns: NIO instance - """ - try: - adapter = self._ethernet_adapters[adapter_number] - except IndexError: - raise DockerError( - "Adapter {adapter_number} doesn't exist on Docker VM '{name}'".format( - name=self.name, adapter_number=adapter_number)) - - adapter.remove_nio(0) - try: - yield from self._delete_ubridge_connection(adapter_number) - except: - pass - - log.info( - "Docker VM '{name}' [{id}]: {nio} removed from adapter {adapter_number}".format( - name=self.name, id=self.id, nio=adapter.host_ifc, - adapter_number=adapter_number)) - - @property - def adapters(self): - """Returns the number of Ethernet adapters for this Docker VM. - - :returns: number of adapters - :rtype: int - """ - return len(self._ethernet_adapters) - - @adapters.setter - def adapters(self, adapters): - """Sets the number of Ethernet adapters for this Docker container. - - :param adapters: number of adapters - """ - - self._ethernet_adapters.clear() - for adapter_number in range(0, adapters): - self._ethernet_adapters.append(EthernetAdapter()) - - log.info( - 'Docker container "{name}" [{id}]: number of Ethernet adapters changed to {adapters}'.format( - name=self._name, - id=self._id, - adapters=adapters)) - - def get_namespace(self): - result = yield from self.manager.execute( - "inspect_container", {"container": self._cid}) - return int(result['State']['Pid']) diff --git a/requirements.txt b/requirements.txt index a623fb77..d40204f2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,5 +2,4 @@ jsonschema>=2.4.0 aiohttp==0.17.4 Jinja2>=2.7.3 raven>=5.2.0 -docker-py==1.4.0 psutil>=3.0.0 diff --git a/setup.py b/setup.py index db28855c..f30bab52 100644 --- a/setup.py +++ b/setup.py @@ -43,7 +43,6 @@ dependencies = [ "aiohttp>=0.15.1", "Jinja2>=2.7.3", "raven>=5.2.0", - "docker-py>=1.4.0", "psutil>=3.0.0" ]