| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 | # Copyright 2015 gRPC authors.## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at##     http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License."""Helpers to run docker instances as jobs."""from __future__ import print_functionimport tempfileimport timeimport uuidimport osimport subprocessimport jobset_DEVNULL = open(os.devnull, 'w')def random_name(base_name):  """Randomizes given base name."""  return '%s_%s' % (base_name, uuid.uuid4())def docker_kill(cid):  """Kills a docker container. Returns True if successful."""  return subprocess.call(['docker','kill', str(cid)],                         stdin=subprocess.PIPE,                         stdout=_DEVNULL,                         stderr=subprocess.STDOUT) == 0def docker_mapped_port(cid, port, timeout_seconds=15):  """Get port mapped to internal given internal port for given container."""  started = time.time()  while time.time() - started < timeout_seconds:    try:      output = subprocess.check_output('docker port %s %s' % (cid, port),                                       stderr=_DEVNULL,                                       shell=True)      return int(output.split(':', 2)[1])    except subprocess.CalledProcessError as e:      pass  raise Exception('Failed to get exposed port %s for container %s.' %                  (port, cid))def wait_for_healthy(cid, shortname, timeout_seconds):  """Wait timeout_seconds for the container to become healthy"""  started = time.time()  while time.time() - started < timeout_seconds:    try:      output = subprocess.check_output(          ['docker', 'inspect', '--format="{{.State.Health.Status}}"', cid],          stderr=_DEVNULL)      if output.strip('\n') == 'healthy':        return    except subprocess.CalledProcessError as e:      pass    time.sleep(1)  raise Exception('Timed out waiting for %s (%s) to pass health check' %                  (shortname, cid))def finish_jobs(jobs):  """Kills given docker containers and waits for corresponding jobs to finish"""  for job in jobs:    job.kill(suppress_failure=True)  while any(job.is_running() for job in jobs):    time.sleep(1)def image_exists(image):  """Returns True if given docker image exists."""  return subprocess.call(['docker','inspect', image],                         stdin=subprocess.PIPE,                         stdout=_DEVNULL,                         stderr=subprocess.STDOUT) == 0def remove_image(image, skip_nonexistent=False, max_retries=10):  """Attempts to remove docker image with retries."""  if skip_nonexistent and not image_exists(image):    return True  for attempt in range(0, max_retries):    if subprocess.call(['docker','rmi', '-f', image],                       stdin=subprocess.PIPE,                       stdout=_DEVNULL,                       stderr=subprocess.STDOUT) == 0:      return True    time.sleep(2)  print('Failed to remove docker image %s' % image)  return Falseclass DockerJob:  """Encapsulates a job"""  def __init__(self, spec):    self._spec = spec    self._job = jobset.Job(spec, newline_on_success=True, travis=True, add_env={})    self._container_name = spec.container_name  def mapped_port(self, port):    return docker_mapped_port(self._container_name, port)  def wait_for_healthy(self, timeout_seconds):    wait_for_healthy(self._container_name, self._spec.shortname, timeout_seconds)  def kill(self, suppress_failure=False):    """Sends kill signal to the container."""    if suppress_failure:      self._job.suppress_failure_message()    return docker_kill(self._container_name)  def is_running(self):    """Polls a job and returns True if given job is still running."""    return self._job.state() == jobset._RUNNING
 |