Change in vdsm[master]: docker integration: basic exposure of REST/CLI api

mpolednik at redhat.com mpolednik at redhat.com
Fri Sep 26 11:14:55 UTC 2014


Martin Polednik has uploaded a new change for review.

Change subject: docker integration: basic exposure of REST/CLI api
......................................................................

docker integration: basic exposure of REST/CLI api

This patch, meant as 0th iteration of docker integration,
introduces two new VDSM verbs: dockerCli and dockerRest.

dockerCli is gateway to docker's command line interface, allowing
engine to run arbitrary docker commands.
dockerCli <command>

dockerRest is gateway to docker's REST api (or remote API) via
UNIX socket, allowing engine to run commands from standard docker
remote API (https://docs.docker.com/reference/api/docker_remote_api/)
dockerRest <method> <url>

Change-Id: I6d958be3b56e20df670896b12b1d6302ed59c491
Signed-off-by: Martin Polednik <mpolednik at redhat.com>
---
M client/vdsClient.py
M lib/vdsm/Makefile.am
A lib/vdsm/docker.py
M vdsm.spec.in
M vdsm/API.py
M vdsm/rpc/BindingXMLRPC.py
6 files changed, 99 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/01/33401/1

diff --git a/client/vdsClient.py b/client/vdsClient.py
index dafca9e..e3e940d 100644
--- a/client/vdsClient.py
+++ b/client/vdsClient.py
@@ -129,6 +129,11 @@
         print "\t%s = %s" % (element, representation)
 
 
+def printResponse(input_list, pretty=True):
+    for item in input_list:
+        print "\t%s" % (item)
+
+
 def printStats(list):
     for conf in list:
         printConf(conf)
@@ -199,6 +204,8 @@
                     printStats(response['statsList'])
             elif 'info' in response:
                 printDict(response['info'], self.pretty)
+            elif 'dockerResponse' in response:
+                print response['dockerResponse']
             else:
                 printDict(response['status'], self.pretty)
         sys.exit(response['status']['code'])
@@ -524,6 +531,14 @@
 
     def do_getAllVmStats(self, args):
         return self.ExecAndExit(self.s.getAllVmStats())
+
+    def do_dockerRest(self, args):
+        method, url = tuple(args[:2])
+        return self.ExecAndExit(self.s.dockerRest(method, url))
+
+    def do_dockerCli(self, args):
+        command = tuple(args)
+        return self.ExecAndExit(self.s.dockerCli(command))
 
     def desktopLogin(self, args):
         vmId, domain, user, password = tuple(args[:4])
@@ -2157,6 +2172,14 @@
                           ('',
                            'Get Statistics info for all existing VMs'
                            )),
+        'dockerRest': (serv.do_dockerRest,
+                       ('<command> <url>',
+                        'Send request to docker remote API'
+                        )),
+        'dockerCli': (serv.do_dockerCli,
+                      ('<command>',
+                       'Send request to docker CLI'
+                       )),
         'getVGList': (serv.getVGList,
                       ('storageType',
                        'List of all VGs.'
diff --git a/lib/vdsm/Makefile.am b/lib/vdsm/Makefile.am
index 4bebf28..1585711 100644
--- a/lib/vdsm/Makefile.am
+++ b/lib/vdsm/Makefile.am
@@ -25,6 +25,7 @@
 	__init__.py \
 	compat.py \
 	define.py \
+	docker.py \
 	exception.py \
 	ipwrapper.py \
 	libvirtconnection.py \
diff --git a/lib/vdsm/docker.py b/lib/vdsm/docker.py
new file mode 100644
index 0000000..1038c9d
--- /dev/null
+++ b/lib/vdsm/docker.py
@@ -0,0 +1,55 @@
+import httplib
+import socket
+import threading
+
+from . import utils
+
+_DOCKER_SOCKET = '/var/run/docker.sock'
+_DOCKER_BIN = utils.CommandPath('docker', '/usr/bin/docker',)
+
+
+class UHTTPConnection(httplib.HTTPConnection):
+
+    def __init__(self, path):
+        httplib.HTTPConnection.__init__(self, 'localhost')
+        self.path = path
+
+    def connect(self):
+        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+        sock.connect(self.path)
+        self.sock = sock
+
+
+class Docker(object):
+    _connection = None
+    _docker = None
+    _connection_lock = threading.Lock()
+    _docker_lock = threading.Lock()
+
+    def __call__(self, command, url=None):
+        if url:
+            self._get().request(command, url)
+            return self._get().getresponse().read()
+        else:
+            cmd = [_DOCKER_BIN.cmd]
+            cmd.extend(command)
+            rc, out, err = utils.execCmd(cmd)
+            return out
+
+    def _get(self):
+        with self._connection_lock:
+            if not self._connection:
+                self._connection = UHTTPConnection(_DOCKER_SOCKET)
+
+            return self._connection
+
+    @classmethod
+    def __enter__(cls):
+        with cls._docker_lock:
+            if not cls._docker:
+                cls._docker = Docker()
+
+        return cls._docker
+
+    def __exit__(self, type, value, traceback):
+        pass
diff --git a/vdsm.spec.in b/vdsm.spec.in
index 56d2579..f3300fe 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -1202,6 +1202,7 @@
 %{python_sitearch}/%{vdsm_name}/config.py*
 %{python_sitearch}/%{vdsm_name}/constants.py*
 %{python_sitearch}/%{vdsm_name}/define.py*
+%{python_sitearch}/%{vdsm_name}/docker.py*
 %{python_sitearch}/%{vdsm_name}/exception.py*
 %{python_sitearch}/%{vdsm_name}/ipwrapper.py*
 %{python_sitearch}/%{vdsm_name}/libvirtconnection.py*
diff --git a/vdsm/API.py b/vdsm/API.py
index 9c47b5f..bd7b537 100644
--- a/vdsm/API.py
+++ b/vdsm/API.py
@@ -47,6 +47,7 @@
 from virt import vm
 from virt import vmstatus
 from vdsm.compat import pickle
+from vdsm.docker import Docker
 from vdsm.define import doneCode, errCode, Kbytes, Mbytes
 import caps
 from vdsm.config import config
@@ -1253,6 +1254,14 @@
         updateTimestamp()
         return {'status': doneCode}
 
+    def dockerRest(self, command, url):
+        with Docker() as docker:
+            return {'status': doneCode, 'dockerResponse': docker(command, url)}
+
+    def dockerCli(self, command):
+        with Docker() as docker:
+            return {'status': doneCode, 'dockerResponse': docker(command)}
+
     def getRoute(self, ip):
         """
         Return the name of the device leading to destination IP or the empty
diff --git a/vdsm/rpc/BindingXMLRPC.py b/vdsm/rpc/BindingXMLRPC.py
index f2dcbdf..a622816 100644
--- a/vdsm/rpc/BindingXMLRPC.py
+++ b/vdsm/rpc/BindingXMLRPC.py
@@ -571,6 +571,14 @@
         api = API.Global()
         return api.ping()
 
+    def dockerRest(self, command, url):
+        api = API.Global()
+        return api.dockerRest(command, url)
+
+    def dockerCli(self, command):
+        api = API.Global()
+        return api.dockerCli(command)
+
     def setSafeNetworkConfig(self):
         api = API.Global()
         return api.setSafeNetworkConfig()
@@ -1019,6 +1027,8 @@
                 (self.editNetwork, 'editNetwork'),
                 (self.setupNetworks, 'setupNetworks'),
                 (self.ping, 'ping'),
+                (self.dockerRest, 'dockerRest'),
+                (self.dockerCli, 'dockerCli'),
                 (self.setSafeNetworkConfig, 'setSafeNetworkConfig'),
                 (self.fenceNode, 'fenceNode'),
                 (self.stop, 'prepareForShutdown'),


-- 
To view, visit http://gerrit.ovirt.org/33401
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I6d958be3b56e20df670896b12b1d6302ed59c491
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Martin Polednik <mpolednik at redhat.com>


More information about the vdsm-patches mailing list