Skip to content

Commit 5fd64ec

Browse files
committed
Added healthcheck
1 parent 412913b commit 5fd64ec

File tree

2 files changed

+63
-7
lines changed

2 files changed

+63
-7
lines changed

lib/schema_checker.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,15 @@ def check_usage_scenario(self, usage_scenario):
9999
Optional("environment"): self.single_or_list(Or(dict,str)),
100100
Optional("ports"): self.single_or_list(Or(str, int)),
101101
Optional("depends_on"): Or([str],dict),
102+
Optional("healthcheck"): {
103+
Optional('test'): Or(list, str),
104+
Optional('interval'): str,
105+
Optional('timeout'): str,
106+
Optional('retries'): int,
107+
Optional('start_period'): str,
108+
# Optional('start_interval'): str, docker CLI does not support this atm
109+
Optional('disable'): bool,
110+
},
102111
Optional("setup-commands"): [str],
103112
Optional("volumes"): self.single_or_list(str),
104113
Optional("folder-destination"):str,

runner.py

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -665,8 +665,6 @@ def order_service_names(service_name, visited=None):
665665

666666
service = services[service_name]
667667
if 'depends_on' in service:
668-
if isinstance(service['depends_on'], dict):
669-
raise RuntimeError(f"Service definition of {service_name} uses the long form of 'depends_on', however, GMT only supports the short form!")
670668
for dep in service['depends_on']:
671669
if dep not in names_ordered:
672670
order_service_names(dep, visited)
@@ -841,6 +839,31 @@ def setup_services(self):
841839
if 'pause-after-phase' in service:
842840
self.__services_to_pause_phase[service['pause-after-phase']] = self.__services_to_pause_phase.get(service['pause-after-phase'], []) + [container_name]
843841

842+
if 'healthcheck' in service: # must come last
843+
if 'disable' in service['healthcheck'] and service['healthcheck']['disable'] is True:
844+
docker_run_string.append('--no-healthcheck')
845+
else:
846+
if 'test' in service['healthcheck']:
847+
docker_run_string.append('--health-cmd')
848+
health_string = service['healthcheck']['test']
849+
if isinstance(service['healthcheck']['test'], list):
850+
health_string = ' '.join(service['healthcheck']['test'])
851+
docker_run_string.append(health_string)
852+
if 'interval' in service['healthcheck']:
853+
docker_run_string.append('--health-interval')
854+
docker_run_string.append(service['healthcheck']['interval'])
855+
if 'timeout' in service['healthcheck']:
856+
docker_run_string.append('--health-timeout')
857+
docker_run_string.append(service['healthcheck']['timeout'])
858+
if 'retries' in service['healthcheck']:
859+
docker_run_string.append('--health-retries')
860+
docker_run_string.append(service['healthcheck']['retries'])
861+
if 'start_period' in service['healthcheck']:
862+
docker_run_string.append('--health-start-period')
863+
docker_run_string.append(service['healthcheck']['start_period'])
864+
if 'start_interval' in service['healthcheck']:
865+
raise RuntimeError('start_interval is not supported atm in healthcheck')
866+
844867
docker_run_string.append(self.clean_image_name(service['image']))
845868

846869
# Before starting the container, check if the dependent containers are "ready".
@@ -849,8 +872,10 @@ def setup_services(self):
849872
# In the future we want to implement an health check to know if dependent containers are actually ready.
850873
if 'depends_on' in service:
851874
for dependent_container in service['depends_on']:
875+
print(f"Waiting for dependent container {dependent_container}")
852876
time_waited = 0
853-
state = ""
877+
state = ''
878+
health = 'healthy' # default because some containers have no health
854879
max_waiting_time = config['measurement']['boot']['wait_time_dependencies']
855880
while time_waited < max_waiting_time:
856881
# TODO: Check health status instead if `healthcheck` is enabled (https://github.com/green-coding-berlin/green-metrics-tool/issues/423)
@@ -861,16 +886,38 @@ def setup_services(self):
861886
text=True
862887
)
863888
state = status_output.strip()
864-
if state == "running":
889+
print(f"State of container '{dependent_container}': {state}.")
890+
891+
if isinstance(service['depends_on'], dict) \
892+
and 'condition' in service['depends_on'][dependent_container]:
893+
894+
condition = service['depends_on'][dependent_container]['condition']
895+
if condition == 'service_healthy':
896+
health_output = subprocess.check_output(
897+
["docker", "container", "inspect", "-f", "{{.State.Health}}", dependent_container],
898+
stderr=subprocess.STDOUT,
899+
encoding='UTF-8'
900+
)
901+
health = health_output.strip()
902+
if health == '<nil>':
903+
raise RuntimeError(f"Health check for dependent_container '{dependent_container}' was requested, but container has no healthcheck implemented!")
904+
print(f"Health of container '{dependent_container}': {health}.")
905+
elif condition == 'service_started':
906+
pass
907+
else:
908+
raise RuntimeError(f"Unsupported condition in healthcheck for service '{service_name}': {condition}")
909+
910+
if state == 'running' and 'healthy' in health:
865911
break
866912

867-
print(f"State of container '{dependent_container}': {state}. Waiting for 1 second")
868-
self.custom_sleep(1)
913+
print('Waiting for 1 second')
914+
time.sleep(1)
869915
time_waited += 1
870916

871-
if state != "running":
917+
if state != 'running':
872918
raise RuntimeError(f"Dependent container '{dependent_container}' of '{container_name}' is not running after waiting for {time_waited} sec! Consider checking your service configuration, the entrypoint of the container or the logs of the container.")
873919

920+
874921
if 'command' in service: # must come last
875922
docker_run_string.append(service['command'])
876923

0 commit comments

Comments
 (0)