Skip to content

Commit

Permalink
HostManager: use "docker compose" instead of "docker-compose" (#383)
Browse files Browse the repository at this point in the history
This also removes the "--docker-compose-bin" argument, which was never
fully propagated, in any case (especially "up" and "down" were
always run with whatever docker-compose was in the PATH); and "inspect"
was (and continues to be) run with the default docker binary in PATH.
  • Loading branch information
mhasself authored Apr 25, 2024
1 parent 2fb5e74 commit e6123b7
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 43 deletions.
10 changes: 2 additions & 8 deletions ocs/agents/host_manager/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,12 @@ class HostManager:
that host (either automatically or on request).
"""

def __init__(self, agent, docker_composes=[], docker_compose_bin=None,
def __init__(self, agent, docker_composes=[],
docker_service_prefix='ocs-'):
self.agent = agent
self.running = False
self.database = {} # key is instance_id (or docker service name).
self.docker_composes = docker_composes
self.docker_compose_bin = docker_compose_bin
self.docker_service_prefix = docker_service_prefix

@inlineCallbacks
Expand Down Expand Up @@ -119,8 +118,7 @@ def _update_docker_services(self, session):
docker_services = {}
for compose in self.docker_composes:
try:
services = yield hm_utils.parse_docker_state(
compose, docker_compose_bin=self.docker_compose_bin)
services = yield hm_utils.parse_docker_state(compose)
this_ok = True
this_msg = f'Successfully parsed {compose} and its service states.'
except Exception as e:
Expand Down Expand Up @@ -690,12 +688,8 @@ def main(args=None):
docker_composes = []
if args.docker_compose:
docker_composes = args.docker_compose.split(',')
docker_compose_bin = args.docker_compose_bin
if args.docker_compose_bin is not None:
docker_compose_bin = os.path.join(os.getcwd(), docker_compose_bin)

host_manager = HostManager(agent, docker_composes=docker_composes,
docker_compose_bin=args.docker_compose_bin,
docker_service_prefix=args.docker_service_prefix)

startup_params = {}
Expand Down
58 changes: 23 additions & 35 deletions ocs/agents/host_manager/drivers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import os
import shutil
import time
import yaml

Expand All @@ -19,8 +18,7 @@ class ManagedInstance(dict):
For instances corresponding to docker services that do not have
a corresponding SCF entry, the value here will be '[docker]'.
- 'instance_id' (str): The agent instance-id, or the docker
service name if the instance is an unmatched docker-compose
service.
service name if the instance is an unmatched docker service.
- 'full_name' (str): agent_class:instance_id
Properties that are given a default value by init function:
Expand Down Expand Up @@ -285,12 +283,9 @@ def errReceived(self, data):
self.lines['stderr'] = self.lines['stderr'][-100:]


def _run_docker_compose(args, docker_compose_bin=None):
# Help avoid some boilerplate.
if docker_compose_bin is None:
docker_compose_bin = shutil.which('docker-compose')
def _run_docker(args):
return utils.getProcessOutputAndValue(
docker_compose_bin, args, env=os.environ)
'docker', args, env=os.environ)


class DockerContainerHelper:
Expand All @@ -301,14 +296,13 @@ class DockerContainerHelper:
"""

def __init__(self, service, docker_compose_bin=None):
def __init__(self, service, docker_bin=None):
self.service = {}
self.status = -1, time.time()
self.killed = False
self.instance_id = service['service']
self.d = None
self.update(service)
self.docker_compose_bin = docker_compose_bin

def update(self, service):
"""Update self.status based on service info (in format returned by
Expand All @@ -323,34 +317,29 @@ def update(self, service):
self.killed = False

def up(self):
self.d = _run_docker_compose(
['-f', self.service['compose_file'],
'up', '-d', self.service['service']],
docker_compose_bin=self.docker_compose_bin)
self.d = _run_docker(
['compose', '-f', self.service['compose_file'],
'up', '-d', self.service['service']])
self.status = None, time.time()

def down(self):
self.d = _run_docker_compose(
['-f', self.service['compose_file'],
'rm', '--stop', '--force', self.service['service']],
docker_compose_bin=self.docker_compose_bin)
self.d = _run_docker(
['compose', '-f', self.service['compose_file'],
'rm', '--stop', '--force', self.service['service']])
self.killed = True


@inlineCallbacks
def parse_docker_state(docker_compose_file, docker_compose_bin=None):
"""Analyze a docker-compose.yaml file to get a list of services.
Using docker-compose ps and docker inspect, determine whether each
def parse_docker_state(docker_compose_file):
"""Analyze a docker compose.yaml file to get a list of services.
Using docker compose ps and docker inspect, determine whether each
service is running or not.
Use docker_compose_bin to pass in the full path to the
docker-compose executable.
Returns:
A dict where the key is the service name and each value is a
dict with the following entries:
- 'compose_file': the path to the docker-compose file
- 'compose_file': the path to the docker compose file
- 'service': service name
- 'container_found': bool, indicates whether a container for
this service was found (whether or not it was running).
Expand All @@ -373,13 +362,12 @@ def parse_docker_state(docker_compose_file, docker_compose_bin=None):
'compose_file': docker_compose_file,
}

# Query docker-compose for container ids...
out, err, code = yield _run_docker_compose(
['-f', docker_compose_file, 'ps', '-q'],
docker_compose_bin=docker_compose_bin)
# Query docker compose for container ids...
out, err, code = yield _run_docker(
['compose', '-f', docker_compose_file, 'ps', '-q'])
if code != 0:
raise RuntimeError("Could not run docker-compose or could not parse "
"docker-compose file; exit code %i, error text: %s" %
raise RuntimeError("Could not run docker compose or could not parse "
"compose.yaml file; exit code %i, error text: %s" %
(code, err))

cont_ids = [line.strip() for line in out.decode('utf8').split('\n')
Expand Down Expand Up @@ -407,19 +395,19 @@ def parse_docker_state(docker_compose_file, docker_compose_bin=None):
@inlineCallbacks
def _inspectContainer(cont_id, docker_compose_file):
"""Run docker inspect on cont_id, return dict with the results."""
out, err, code = yield utils.getProcessOutputAndValue(
'docker', ['inspect', cont_id], env=os.environ)
out, err, code = yield _run_docker(
['inspect', cont_id])
if code != 0 and 'No such object' in err.decode('utf8'):
# This is likely due to a race condition where some
# container was brought down since we ran docker-compose.
# container was brought down since we ran docker compose.
# Return None to indicate this -- caller should just ignore for now.
print(f'(_inspectContainer: warning, no such object: {cont_id}')
return None
elif code != 0:
raise RuntimeError(
f'Trouble running "docker inspect {cont_id}".\n'
f'stdout: {out}\n stderr {err}')
# Reconcile config against docker-compose ...
# Reconcile config against docker compose ...
info = yaml.safe_load(out)[0]
config = info['Config']['Labels']
_dc_file = os.path.join(config['com.docker.compose.project.working_dir'],
Expand Down

0 comments on commit e6123b7

Please sign in to comment.