use wrapped cli to create containers
This commit is contained in:
parent
b4a1721213
commit
ef779233b9
|
@ -14,7 +14,7 @@ hard_config = {
|
||||||
"run_iptables_with_sudo":True,
|
"run_iptables_with_sudo":True,
|
||||||
"clore_iptables_rules":[
|
"clore_iptables_rules":[
|
||||||
"-A INPUT -s <subnet> -j DROP",
|
"-A INPUT -s <subnet> -j DROP",
|
||||||
"-I DOCKER-USER -i <interface> -d <subnet> -j DROP"
|
"-I FORWARD -i <interface> -d <subnet> -j DROP"
|
||||||
],
|
],
|
||||||
"clore_br_first_allowed_octet":"172",
|
"clore_br_first_allowed_octet":"172",
|
||||||
"ws_peers_recheck_interval": 300,
|
"ws_peers_recheck_interval": 300,
|
||||||
|
@ -31,7 +31,8 @@ hard_config = {
|
||||||
"max_container_log_size": 262144, # Characters
|
"max_container_log_size": 262144, # Characters
|
||||||
"container_log_streaming_interval": 2, # Seconds
|
"container_log_streaming_interval": 2, # Seconds
|
||||||
"maximum_service_loop_time": 900, # Seconds, failsafe variable - if service is stuck processing longer than this timeframe it will lead into restarting the app
|
"maximum_service_loop_time": 900, # Seconds, failsafe variable - if service is stuck processing longer than this timeframe it will lead into restarting the app
|
||||||
"maximum_pull_service_loop_time": 14400 # Exception for image pulling
|
"maximum_pull_service_loop_time": 14400, # Exception for image pulling
|
||||||
|
"creation_engine": "wrapper" # "wrapper" or "sdk" | Wrapper - wrapped docker cli, SDK - docker sdk
|
||||||
}
|
}
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='Example argparse usage')
|
parser = argparse.ArgumentParser(description='Example argparse usage')
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
from lib import logging as logging_lib
|
||||||
|
from lib import config as config_module
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import re, os
|
||||||
|
import signal
|
||||||
|
import docker
|
||||||
|
|
||||||
|
config = config_module.config
|
||||||
|
log = logging_lib.log
|
||||||
|
|
||||||
|
def create_container(container_options, ip=None, docker_gpus=False, timeout=30):
|
||||||
|
# Sanitize and validate input
|
||||||
|
container_options = sanitize_input(container_options)
|
||||||
|
|
||||||
|
command = ["docker", "run", "--detach", "--tty"]
|
||||||
|
|
||||||
|
if "name" in container_options:
|
||||||
|
command.extend(["--name", container_options["name"]])
|
||||||
|
|
||||||
|
if "network_mode" in container_options:
|
||||||
|
command.extend(["--network", container_options["network_mode"]])
|
||||||
|
|
||||||
|
if "cap_add" in container_options:
|
||||||
|
for cap in container_options["cap_add"]:
|
||||||
|
command.extend(["--cap-add", cap])
|
||||||
|
|
||||||
|
if "volumes" in container_options:
|
||||||
|
for volume_host, volume_container in container_options["volumes"].items():
|
||||||
|
bind = f"{volume_host}:{volume_container['bind']}"
|
||||||
|
if "mode" in volume_container:
|
||||||
|
bind += f":{volume_container['mode']}"
|
||||||
|
command.extend(["--volume", bind])
|
||||||
|
|
||||||
|
if "ports" in container_options:
|
||||||
|
for port_container, port_host in container_options["ports"].items():
|
||||||
|
command.extend(["-p", f"{port_host}:{port_container}"])
|
||||||
|
|
||||||
|
if "environment" in container_options:
|
||||||
|
for env_var, env_value in container_options["environment"].items():
|
||||||
|
command.extend(["-e", f"{env_var}={env_value}"])
|
||||||
|
|
||||||
|
if "log_config" in container_options:
|
||||||
|
log_config = container_options["log_config"]
|
||||||
|
if isinstance(log_config, dict):
|
||||||
|
for key, value in log_config["Config"].items():
|
||||||
|
log_option = (f"{key}={value}")
|
||||||
|
command.extend(["--log-opt", log_option])
|
||||||
|
command.extend(["--log-driver", log_config["Type"]])
|
||||||
|
else:
|
||||||
|
log.debug("Invalid log_config format. Skipping log configuration.")
|
||||||
|
|
||||||
|
if "runtime" in container_options:
|
||||||
|
command.extend(["--runtime", container_options["runtime"]])
|
||||||
|
if docker_gpus:
|
||||||
|
if type(docker_gpus)==list:
|
||||||
|
command.extend(['--gpus', '"device=' + ','.join(str(gpu_id) for gpu_id in docker_gpus) + '"'])
|
||||||
|
else:
|
||||||
|
command.extend(["--gpus", "all"])
|
||||||
|
|
||||||
|
if "storage_opt" in container_options:
|
||||||
|
for storage_opt, value in container_options["storage_opt"].items():
|
||||||
|
command.extend(["--storage-opt", f"{storage_opt}={value}"])
|
||||||
|
|
||||||
|
if "entrypoint" in container_options:
|
||||||
|
command.extend(["--entrypoint", container_options["entrypoint"]])
|
||||||
|
|
||||||
|
if ip:
|
||||||
|
command.extend(["--ip", ip])
|
||||||
|
|
||||||
|
command.append(container_options["image"])
|
||||||
|
|
||||||
|
try:
|
||||||
|
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
|
||||||
|
try:
|
||||||
|
output, error = process.communicate(timeout=timeout)
|
||||||
|
if process.returncode == 0:
|
||||||
|
container_id = output.strip()
|
||||||
|
return container_id
|
||||||
|
else:
|
||||||
|
print(f"Error creating container: {error}")
|
||||||
|
return None
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
process.send_signal(signal.SIGTERM)
|
||||||
|
process.kill()
|
||||||
|
print("Timeout exceeded while creating container.")
|
||||||
|
return None
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(f"Error creating container: {e.output}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def sanitize_input(container_options):
|
||||||
|
sanitized_options = {}
|
||||||
|
for key, value in container_options.items():
|
||||||
|
if isinstance(value, str):
|
||||||
|
# Remove any potential shell injection or escapes
|
||||||
|
sanitized_value = re.sub(r'[`$\\\'\"]', '', value)
|
||||||
|
sanitized_options[key] = sanitized_value
|
||||||
|
elif isinstance(value, dict):
|
||||||
|
sanitized_options[key] = sanitize_input(value)
|
||||||
|
elif isinstance(value, list):
|
||||||
|
sanitized_list = []
|
||||||
|
for item in value:
|
||||||
|
if isinstance(item, str):
|
||||||
|
sanitized_item = re.sub(r'[`$\\\'\"]', '', item)
|
||||||
|
sanitized_list.append(sanitized_item)
|
||||||
|
elif isinstance(item, dict):
|
||||||
|
sanitized_list.append(sanitize_input(item))
|
||||||
|
sanitized_options[key] = sanitized_list
|
||||||
|
else:
|
||||||
|
sanitized_options[key] = value
|
||||||
|
return sanitized_options
|
|
@ -1,5 +1,6 @@
|
||||||
from lib import config as config_module
|
from lib import config as config_module
|
||||||
from lib import logging as logging_lib
|
from lib import logging as logging_lib
|
||||||
|
from lib import docker_cli_wrapper
|
||||||
from lib import docker_interface
|
from lib import docker_interface
|
||||||
from lib import get_specs
|
from lib import get_specs
|
||||||
import docker
|
import docker
|
||||||
|
@ -44,6 +45,7 @@ def deploy(validated_containers):
|
||||||
try:
|
try:
|
||||||
|
|
||||||
image_ready = False
|
image_ready = False
|
||||||
|
docker_gpus = None
|
||||||
for local_image in local_images:
|
for local_image in local_images:
|
||||||
if local_image.replace(':latest','')==validated_container["image"].replace(':latest',''):
|
if local_image.replace(':latest','')==validated_container["image"].replace(':latest',''):
|
||||||
image_ready = True
|
image_ready = True
|
||||||
|
@ -76,14 +78,16 @@ def deploy(validated_containers):
|
||||||
|
|
||||||
if "network" in validated_container:
|
if "network" in validated_container:
|
||||||
container_options["network_mode"]=validated_container["network"]
|
container_options["network_mode"]=validated_container["network"]
|
||||||
if "ip" in validated_container:
|
if "ip" in validated_container and config.creation_engine=="sdk":
|
||||||
del container_options["network_mode"]
|
del container_options["network_mode"]
|
||||||
|
|
||||||
if "gpus" in validated_container and type(validated_container["gpus"])==bool:
|
if "gpus" in validated_container and type(validated_container["gpus"])==bool:
|
||||||
container_options["runtime"]="nvidia"
|
container_options["runtime"]="nvidia"
|
||||||
|
docker_gpus=True
|
||||||
container_options["device_requests"].append(docker.types.DeviceRequest(count=-1, capabilities=[['gpu']]))
|
container_options["device_requests"].append(docker.types.DeviceRequest(count=-1, capabilities=[['gpu']]))
|
||||||
elif "gpus" in validated_container and type(validated_container["gpus"])==list:
|
elif "gpus" in validated_container and type(validated_container["gpus"])==list:
|
||||||
container_options["runtime"]="nvidia"
|
container_options["runtime"]="nvidia"
|
||||||
|
docker_gpus=validated_container["gpus"]
|
||||||
container_options["device_requests"].append(docker.types.DeviceRequest(
|
container_options["device_requests"].append(docker.types.DeviceRequest(
|
||||||
count=-1,
|
count=-1,
|
||||||
capabilities=[['gpu']],
|
capabilities=[['gpu']],
|
||||||
|
@ -118,6 +122,9 @@ def deploy(validated_containers):
|
||||||
container_options["entrypoint"]=validated_container["entrypoint_command"]
|
container_options["entrypoint"]=validated_container["entrypoint_command"]
|
||||||
|
|
||||||
if not validated_container["name"] in created_container_names and image_ready:
|
if not validated_container["name"] in created_container_names and image_ready:
|
||||||
|
if config.creation_engine == "wrapper":
|
||||||
|
docker_cli_wrapper.create_container(container_options, ip=(validated_container["ip"] if "ip" in validated_container else None), docker_gpus=docker_gpus)
|
||||||
|
else:
|
||||||
container = client.containers.create(**container_options)
|
container = client.containers.create(**container_options)
|
||||||
if "ip" in validated_container:
|
if "ip" in validated_container:
|
||||||
client.networks.get(validated_container["network"] if "network" in validated_container else "clore-br0").connect(container, ipv4_address=validated_container["ip"])
|
client.networks.get(validated_container["network"] if "network" in validated_container else "clore-br0").connect(container, ipv4_address=validated_container["ip"])
|
||||||
|
|
Loading…
Reference in New Issue