-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit aa4674c
Showing
16 changed files
with
711 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
__pycache__/ | ||
.DS_Store | ||
drolex/ | ||
.dockerignore | ||
.gitignore | ||
*.md | ||
*.pyc | ||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
.DS_Store | ||
*.pyc | ||
drolex/ | ||
.idea | ||
__pycache__/ | ||
pip-selfcheck.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
FROM python:3.6.4-alpine3.7 | ||
|
||
ADD . /opt/docker | ||
|
||
WORKDIR /opt/docker | ||
|
||
RUN pip install -r requirements.txt | ||
|
||
ENTRYPOINT [ "python3", "drolex.py"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
Copyright (c) 2018, Qvantel | ||
All rights reserved. | ||
|
||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions are met: | ||
* Redistributions of source code must retain the above copyright | ||
notice, this list of conditions and the following disclaimer. | ||
* Redistributions in binary form must reproduce the above copyright | ||
notice, this list of conditions and the following disclaimer in the | ||
documentation and/or other materials provided with the distribution. | ||
* Neither the name of the <organization> nor the | ||
names of its contributors may be used to endorse or promote products | ||
derived from this software without specific prior written permission. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
DISCLAIMED. IN NO EVENT SHALL QVANTEL BE LIABLE FOR ANY | ||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# Drolex - Docker Run Online Extractor | ||
|
||
Drolex is a command-line tool (for now) for extracting docker run commands from running containers. At this point it is | ||
meant for simple use cases, so it might miss more advanced parameters. | ||
|
||
## Use | ||
|
||
You can always run the tool with the `--help` flag to show the usage info: | ||
|
||
```shell | ||
usage: drolex.py [-h] [--conn_uri CONN_URI] [--tls_cert TLS_CERT] | ||
[--loglevel {DEBUG,INFO,WARNING,ERROR}] --ID ID | ||
[--order ORDER] | ||
|
||
DROLEX - Docker Run OnLine EXtractor | ||
|
||
optional arguments: | ||
-h, --help show this help message and exit | ||
--conn_uri CONN_URI Address and port of docker server Ex: --conn_uri | ||
"tcp://127.0.0.1:1234" (Default: | ||
unix://var/run/docker.sock) | ||
--loglevel {DEBUG,INFO,WARNING,ERROR} | ||
LogLevel of the app. (Default: INFO) | ||
--ID ID Container ID to check | ||
--order ORDER Order in which to print the different parts of the | ||
docker run command (Default: Mode,HostConfig,NetworkSe | ||
ttings,Exposed,Ports,Mounts,Env,Name,Image,Args) | ||
|
||
``` | ||
|
||
Note that, for remote use, the Docker daemon must be listening on it's TCP port. | ||
To configure it you must edit `/etc/sysconfig/docker` and add the following in the `OPTIONS` field: | ||
```shell | ||
-H unix://var/run/docker.sock -H tcp://0.0.0.0:2375 | ||
``` | ||
|
||
after that reload the daemon's config and relaunch it: | ||
```shell | ||
sudo systemctl daemon-reload | ||
sudo systemctl restart docker.service | ||
``` | ||
|
||
### Running from source | ||
|
||
To run from source, the following command can be used to install the app's dependencies: | ||
|
||
```shell | ||
pip install -r requirements.txt | ||
``` | ||
|
||
After that the tool can be run through drolex.py | ||
|
||
### Running the container (recommended) | ||
|
||
Drolex can also be run as a container by using the following command: | ||
|
||
```shell | ||
docker run -m 128m -it --rm -v /var/run/docker.sock:/var/run/docker.sock --name drolex qvantel/drolex:0.2.0 --ID zookeeper | ||
``` | ||
|
||
> Note: | ||
> Even though it's dockerized, the arguments placed after the image parameter behave in the same way as the python | ||
> script when running from source. | ||
## TODO | ||
|
||
This application is still in development as the goal is to have it run as a service with a web ui and connect to other | ||
remote server's docker daemons securely. | ||
|
||
- TLS connection to the docker service | ||
- UI |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,230 @@ | ||
""" | ||
Copyright (c) 2018, Qvantel | ||
All rights reserved. | ||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions are met: | ||
* Redistributions of source code must retain the above copyright | ||
notice, this list of conditions and the following disclaimer. | ||
* Redistributions in binary form must reproduce the above copyright | ||
notice, this list of conditions and the following disclaimer in the | ||
documentation and/or other materials provided with the distribution. | ||
* Neither the name of the <organization> nor the | ||
names of its contributors may be used to endorse or promote products | ||
derived from this software without specific prior written permission. | ||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
DISCLAIMED. IN NO EVENT SHALL QVANTEL BE LIABLE FOR ANY | ||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
DROLEX - Docker Run OnLine EXtractor | ||
This service reads a currently running docker and shows the command line used to run it. | ||
""" | ||
# System Imports | ||
import logging | ||
import sys | ||
import importlib | ||
from functools import reduce | ||
# Self project imports | ||
from errors import DrolexException | ||
# Non default packages test to run import | ||
try: | ||
import docker | ||
except ImportError: | ||
logging.exception('Error importing Docker module. Check that "pip install docker" is already done', exc_info=False) | ||
sys.exit(10) | ||
|
||
|
||
class Drolex: | ||
def __init__(self, conn_uri='unix://var/run/docker.sock', tls_conf=False, loglevel='DEBUG', logfile=None): | ||
self.__setLogging(level=loglevel,logfile=logfile) | ||
self.__setClient(conn_uri=conn_uri, tls_conf=tls_conf) | ||
|
||
|
||
def __setLogging(self, level='DEBUG', logfile=None): | ||
self.debug = False | ||
if level=='DEBUG': | ||
self.debug=True | ||
self.log = logging.getLogger(self.__class__.__name__) | ||
self.log.setLevel(getattr(logging, level)) | ||
format = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") | ||
|
||
if not logfile: | ||
ch = logging.StreamHandler(sys.stdout) | ||
ch.setFormatter(format) | ||
self.log.addHandler(ch) | ||
self.log.debug("Logging system setup done to STDOUT") | ||
else: | ||
# Used if need to write to a logfile | ||
try: | ||
fh = logging.FileHandler(logfile) | ||
fh.setFormatter(format) | ||
self.log.addHandler(fh) | ||
self.log.debug("Logging system setup done to %s", logfile) | ||
except Exception: | ||
if self.debug: | ||
logging.exception("Error logging to logfile", exc_info=True) | ||
else: | ||
logging.exception("Error logging to logfile", exc_info=False) | ||
|
||
|
||
''' | ||
Create the connection to the docker daemon API | ||
''' | ||
def __setClient(self, conn_uri='unix://var/run/docker.sock', tls_conf=False): | ||
try: | ||
self.client = docker.APIClient( | ||
base_url=conn_uri, | ||
tls=tls_conf, | ||
user_agent="SWAT/Drolex", | ||
version='auto' | ||
) | ||
self.log.debug("Connected to DockerDaemon on {0}".format(conn_uri)) | ||
self.log.debug("Server version is: {0}".format(self.client.version())) | ||
except Exception as e: | ||
if self.debug: | ||
self.log.error("Unable to create DockerClient",exc_info=True) | ||
else: | ||
self.log.error("Unable to create DockerClient",exc_info=False) | ||
|
||
raise DrolexException("Unable to instance the DockerClient: {0}".format(e)) | ||
|
||
|
||
''' | ||
Get the configuration dictionary from an specific container name or ID | ||
INPUT: | ||
str - Container ID or Name | ||
OUTPUT: | ||
{dict} - Container config dictionary | ||
''' | ||
def get_config(self, dockerID): | ||
# Check that dockerID is a String | ||
if not isinstance(dockerID, str): | ||
self.log.error("DockerID provided is not a valid String") | ||
raise DrolexException("DockerID must be a valid String: {0}".format(dockerID)) | ||
try: | ||
config = self.client.inspect_container(dockerID) | ||
image_config = self.client.inspect_image(config["Image"]) | ||
config["Config"].update({"ImageEnv": image_config["Config"]["Env"], "ImagePorts": image_config["Config"].get("ExposedPorts", [])}) | ||
image_cmd = (image_config["Config"]["Entrypoint"] or []) + (image_config["Config"]["Cmd"] or []) | ||
config["Args"] = {"ImageCmd": image_cmd, "Cmd": config["Args"]} | ||
if self.debug: | ||
import pprint | ||
pprinter = pprint.PrettyPrinter(indent=4) | ||
pprinter.pprint(config) | ||
|
||
except docker.errors.NotFound: | ||
self.log.error("Unable to find DockerID: {0}".format(dockerID)) | ||
except docker.errors.APIError as error: | ||
self.log.error("Error in Docker API call.") | ||
if self.debug: | ||
self.log.debug("DOCKER API TRACEBACK: {0}".format(error)) | ||
except docker.errors.InvalidVersion as versioning: | ||
self.log.error("Missmatch in Docker API client->Server version") | ||
if self.debug: | ||
self.log.debug("DOCKER API TRACEBACK: {0}".format(versioning)) | ||
|
||
return config | ||
|
||
|
||
''' | ||
Generate a docker run command following a template. It will use the given order then add any | ||
remaining elements to the end. | ||
INPUT: | ||
{dict} - Docker command parts | ||
list - Order in which the parts of the command should be arranged | ||
OUTPUT: | ||
str - Docker run command | ||
''' | ||
def to_docker_run(self, parts, order): | ||
rest = reduce(lambda acc, key: acc + (parts[key] if key not in order and key != "ExtraNetworks" else ""), parts, "") | ||
command = "docker run " + reduce(lambda acc, key: acc + parts[key], order, "") + rest | ||
return command | ||
|
||
|
||
''' | ||
Generate a docker network connect command. | ||
INPUT: | ||
list - List of networks to create docker network connect commands for | ||
str - Name of the container to connect | ||
OUTPUT: | ||
str - Docker network connect command | ||
''' | ||
def to_docker_network_connect(self, networks, container): | ||
result = reduce(lambda acc, item: acc + "; docker network connect " + item["Options"] + " " + item["Name"] + " " + container + " ", networks, "") | ||
result = result + "; docker restart " + container + " " | ||
return result | ||
|
||
|
||
''' | ||
Dinamically get the content of a docker config output and look in the utils available to | ||
proccess every key to generate the desired command line | ||
If no util/KEY is available write in debug but not in error a message | ||
INPUT: | ||
{dict} - An output object from docker.APIClient.inspect_container call | ||
OUTPUT: | ||
{dict} - A join of all the available dinamic objects for the input dict | ||
''' | ||
def rerun(self, configdata, order): | ||
out_cmd = {} | ||
for key in configdata: | ||
# self.log.debug("Available Key in config: {0}".format(key)) | ||
try: | ||
module_name = "utils." + key | ||
dynmod = importlib.import_module(module_name) | ||
self.log.debug("Module {0} imported".format(key)) | ||
dynclass = getattr(dynmod, key) | ||
self.log.debug("Class loaded") | ||
processor = dynclass(configdata[key]) | ||
self.log.debug("Running processor for config key: {0}".format(key)) | ||
out_cmd.update(processor.run()) | ||
except ImportError: | ||
self.log.debug("No processor found for config key: {0}".format(key)) | ||
except Exception as e: | ||
self.log.exception(e) | ||
print(self.to_docker_run(out_cmd, order.split(","))) | ||
if out_cmd["ExtraNetworks"]: | ||
print(self.to_docker_network_connect(out_cmd["ExtraNetworks"], configdata["Name"].replace("/",""))) | ||
|
||
|
||
# Self test use | ||
if __name__ == '__main__': | ||
from drolex import Drolex | ||
import argparse | ||
|
||
# Prepare the argparse | ||
parser = argparse.ArgumentParser(description='DROLEX - Docker Run OnLine EXtractor') | ||
parser.add_argument('--conn_uri', | ||
help='Address and port of docker server Ex: --conn_uri "tcp://127.0.0.1:1234" (Default: %(default)s)', | ||
default='unix://var/run/docker.sock') | ||
#parser.add_argument('--tls_cert', help='Client TLS cert to connect to server', | ||
# required=False) | ||
parser.add_argument('--loglevel', help='LogLevel of the app. (Default: %(default)s)', | ||
choices=['DEBUG', 'INFO', 'WARNING', 'ERROR'], default='INFO') | ||
parser.add_argument('--ID', help="Container ID to check", required=True) | ||
parser.add_argument('--order', | ||
help='Order in which to print the different parts of the docker run command (Default: %(default)s)', | ||
default='Mode,HostConfig,NetworkSettings,Exposed,Ports,Mounts,Env,Name,Image,Args') | ||
|
||
# Run the code | ||
try: | ||
# Proccess the arguments | ||
args = vars(parser.parse_args()) | ||
|
||
# Some error occurred | ||
except: | ||
sys.exit(1) | ||
|
||
drolex = Drolex(conn_uri=args['conn_uri'], | ||
loglevel=args['loglevel']) | ||
# Run the update method | ||
drolex.rerun(drolex.get_config(dockerID=args['ID']), args['order']) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
""" | ||
Copyright (c) 2018, Qvantel | ||
All rights reserved. | ||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions are met: | ||
* Redistributions of source code must retain the above copyright | ||
notice, this list of conditions and the following disclaimer. | ||
* Redistributions in binary form must reproduce the above copyright | ||
notice, this list of conditions and the following disclaimer in the | ||
documentation and/or other materials provided with the distribution. | ||
* Neither the name of the <organization> nor the | ||
names of its contributors may be used to endorse or promote products | ||
derived from this software without specific prior written permission. | ||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
DISCLAIMED. IN NO EVENT SHALL QVANTEL BE LIABLE FOR ANY | ||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
""" | ||
class DrolexException(Exception): | ||
def __init__(self, message): | ||
self.message = message | ||
|
||
def __str__(self): | ||
return(repr(self.message)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
docker |
Oops, something went wrong.