Ejemplo n.º 1
0
    def run_image(self): # returns RunCondition
        # pylint: disable=import-outside-toplevel, cyclic-import
        from miniboss.services import Service
        client = DockerClient.get_client()
        self.service.env = Context.extrapolate_values(self.service.env)
        # If there are any running with the name prefix, connected to the same
        # network, skip creating
        existings = client.existing_on_network(self.container_name_prefix,
                                               self.options.network)
        if existings:
            self._start_existing(existings)
            if self.run_condition.state in [RunCondition.STARTED, RunCondition.RUNNING]:
                return
        logger.info("Creating new container for service %s", self.service.name)
        self.service.pre_start()
        if self.service.pre_start.__func__ is not Service.pre_start:
            logger.info("pre_start for service %s ran", self.service.name)
        self.run_condition.pre_started()
        client.run_service_on_network(self.container_name_prefix,
                                      self.service,
                                      self.options.network)

        self.run_condition.started()
        if not self.ping():
            self._fail()
            return
        self.service.post_start()
        self.run_condition.post_started()
        if self.service.post_start.__func__ is not Service.post_start:
            logger.info("post_start for service %s ran", self.service.name)
Ejemplo n.º 2
0
 def _start_existing(self, existings):
     # pylint: disable=fixme
     # TODO fix this; it should be able to deal with multiple existing
     # containers
     existing = existings[0]
     if existing.status == 'running':
         logger.info("Found running container for %s, not starting a new one",
                     self.service.name)
         self.run_condition.already_running()
         return
     client = DockerClient.get_client()
     if existing.status == 'exited':
         existing_env = container_env(existing)
         diff_keys = differing_keys(self.service.env, existing_env)
         if diff_keys:
             logger.info("Differing env key(s) in existing container for service %s: %s",
                         self.service.name, ",".join(diff_keys))
         start_new = (self.service.always_start_new or
                      self.service.image not in existing.image.tags or
                      bool(diff_keys))
         if not start_new:
             logger.info("There is an existing container for %s, not creating a new one",
                         self.service.name)
             self.run_condition.started()
             client.run_container(existing.id)
             if not self.ping():
                 self._fail()
    def test_run_container(self):
        client = DockerClient.get_client()
        client.create_network('miniboss-test-network')
        self.network_cleanup.append('miniboss-test-network')

        class TestService(miniboss.Service):
            name = 'test-service'
            image = 'nginx'
            ports = {80: 8085}

        service = TestService()
        container_name = client.run_service_on_network(
            'miniboss-test-service', service,
            Network(name='miniboss-test-network', id=""))
        self.container_cleanup.append(container_name)
        resp = requests.get('http://localhost:8085')
        assert resp.status_code == 200
        lib_client = get_lib_client()
        container = lib_client.containers.get(container_name)
        container.stop()
        # Let's make sure it's not running
        with pytest.raises(Exception):
            resp = requests.get('http://localhost:8085')
        # and restart it
        client.run_container(container.id)
        resp = requests.get('http://localhost:8085')
        assert resp.status_code == 200
    def test_print_error_on_container_dead(self):
        lib_client = get_lib_client()
        context = tempfile.mkdtemp()
        with open(os.path.join(context, 'Dockerfile'), 'w') as dockerfile:
            dockerfile.write("""FROM bash
WORKDIR /
COPY fail.sh /
RUN chmod +x /fail.sh
CMD ["/fail.sh"]""")
        with open(os.path.join(context, 'fail.sh'), 'w') as index:
            index.write("echo 'Going down' && exit 1")
        lib_client.images.build(path=context, tag="crashing-container")
        self.image_cleanup.append('crashing-container')
        client = DockerClient.get_client()
        client.create_network('miniboss-test-network')
        self.network_cleanup.append('miniboss-test-network')

        class FailingService(miniboss.Service):
            name = 'failing-service'
            image = 'crashing-container'

        service = FailingService()
        with pytest.raises(
                exceptions.ContainerStartException) as exception_context:
            client.run_service_on_network(
                'miniboss-failing-service', service,
                Network(name='miniboss-test-network', id=""))
        exception = exception_context.value
        self.container_cleanup.append(exception.container_name)
        assert exception.logs == "Going down\n"
 def test_create_remove_network(self):
     client = DockerClient.get_client()
     client.create_network('miniboss-test-network')
     lib_client = get_lib_client()
     networks = lib_client.networks.list()
     assert 'miniboss-test-network' in [n.name for n in networks]
     client.remove_network('miniboss-test-network')
     networks = lib_client.networks.list()
     assert 'miniboss-test-network' not in [n.name for n in networks]
Ejemplo n.º 6
0
 def build_image(self):
     client = DockerClient.get_client()
     time_tag = datetime.now().strftime("%Y-%m-%d-%H%M")
     image_tag = "{:s}-{:s}".format(self.service.name, time_tag)
     build_dir = os.path.join(self.options.run_dir, self.service.build_from)
     logger.info("Building image with tag %s for service %s from directory %s",
                 image_tag, self.service.name, build_dir)
     client.build_image(build_dir, self.service.dockerfile, image_tag)
     self.run_condition.build_image()
     return image_tag
 def test_check_image_missing_tag(self):
     lib_client = get_lib_client()
     lib_client.images.pull('registry:2')
     hub_container = lib_client.containers.run('registry:2',
                                               detach=True,
                                               ports={5000: 5000})
     self.container_cleanup.append(hub_container.name)
     client = DockerClient.get_client()
     with pytest.raises(exceptions.DockerException):
         client.check_image("localhost:5000/this-repo:not-exist")
Ejemplo n.º 8
0
 def stop_all(self, options: Options):
     docker = DockerClient.get_client()
     self.running_context = RunningContext(self.all_by_name, options)
     while not (self.running_context.done
                or self.running_context.failed_services):
         for agent in self.running_context.ready_to_stop:
             agent.stop_service()
         time.sleep(0.01)
     if options.remove and not self.excluded:
         docker.remove_network(options.network.name)
    def test_build_image(self):
        lib_client = get_lib_client()
        context = tempfile.mkdtemp()
        with open(os.path.join(context, 'Dockerfile'), 'w') as dockerfile:
            dockerfile.write("""FROM nginx
COPY index.html /usr/share/nginx/html""")
        with open(os.path.join(context, 'index.html'), 'w') as index:
            index.write("ALL GOOD")
        client = DockerClient.get_client()
        client.build_image(context, 'Dockerfile', 'temporary-tag')
        images = lib_client.images.list(name="temporary-tag")
        assert len(images) == 1
Ejemplo n.º 10
0
 def _stop_container(self, remove):
     client = DockerClient.get_client()
     existings = client.existing_on_network(self.container_name_prefix,
                                            self.options.network)
     if not existings:
         logging.info("No containers to stop for %s", self.service.name)
     for existing in existings:
         if existing.status == 'running':
             existing.stop(timeout=self.options.timeout)
             logging.info("Stopped container %s", existing.name)
         if remove:
             existing.remove()
             logging.info("Removed container %s", existing.name)
Ejemplo n.º 11
0
 def start_all(self, options: Options):
     docker = DockerClient.get_client()
     network = docker.create_network(options.network.name)
     options.network.id = network.id
     self.running_context = RunningContext(self.all_by_name, options)
     while not self.running_context.done:
         for agent in self.running_context.ready_to_start:
             agent.start_service()
         time.sleep(0.01)
     failed = []
     if self.running_context.failed_services:
         failed = [x.name for x in self.running_context.failed_services]
         logger.error("Failed to start following services: %s",
                      ",".join(failed))
     return [x for x in self.all_by_name.keys() if x not in failed]
Ejemplo n.º 12
0
    def test_run_service_volume_mount(self):
        client = DockerClient.get_client()
        client.create_network('miniboss-test-network')
        self.network_cleanup.append('miniboss-test-network')
        #----------------------------
        context = tempfile.mkdtemp()
        with open(os.path.join(context, 'Dockerfile'), 'w') as dockerfile:
            dockerfile.write("""FROM python:3.7
WORKDIR /app
RUN pip install flask
COPY app.py .
CMD ["python3", "app.py"]""")
        with open(os.path.join(context, 'app.py'), 'w') as app_file:
            app_file.write("""
from flask import Flask
app = Flask('the-app')

@app.route("/")
def index():
    with open("/mnt/volume1/key.txt", 'r') as key_file:
        retval = key_file.read()
    return retval

app.run(host='0.0.0.0', port=8080)
""")
        lib_client = get_lib_client()
        lib_client.images.build(path=context, tag="mounted-container")
        self.image_cleanup.append("mounted-container")
        #----------------------------
        mount_dir = tempfile.mkdtemp()
        key = str(uuid.uuid4())
        with open(os.path.join(mount_dir, 'key.txt'), 'w') as keyfile:
            keyfile.write(key)

        class TestService(miniboss.Service):
            name = 'test-service'
            image = 'mounted-container'
            ports = {8080: 8080}
            volumes = {mount_dir: {'bind': '/mnt/volume1', 'mode': 'ro'}}

        service = TestService()
        container_name = client.run_service_on_network(
            'miniboss-test-service', service,
            Network(name='miniboss-test-network', id=""))
        self.container_cleanup.append(container_name)
        resp = requests.get('http://localhost:8080')
        assert resp.status_code == 200
        assert resp.text == key
Ejemplo n.º 13
0
    def test_run_service_on_network(self):
        client = DockerClient.get_client()
        client.create_network('miniboss-test-network')
        self.network_cleanup.append('miniboss-test-network')

        class TestService(miniboss.Service):
            name = 'test-service'
            image = 'nginx'
            ports = {80: 8085}

        service = TestService()
        container_name = client.run_service_on_network(
            'miniboss-test-service', service,
            Network(name='miniboss-test-network', id=""))
        self.container_cleanup.append(container_name)
        resp = requests.get('http://localhost:8085')
        assert resp.status_code == 200
        lib_client = get_lib_client()
        containers = lib_client.containers.list()
        assert container_name in [c.name for c in containers]
        network = lib_client.networks.get('miniboss-test-network')
        assert len(network.containers) == 1
        assert network.containers[0].name == container_name
Ejemplo n.º 14
0
    def test_check_image_download_from_repo(self):
        lib_client = get_lib_client()
        context = tempfile.mkdtemp()
        with open(os.path.join(context, 'Dockerfile'), 'w') as dockerfile:
            dockerfile.write("""FROM nginx
COPY index.html /usr/share/nginx/html""")
        with open(os.path.join(context, 'index.html'), 'w') as index:
            index.write("ALL GOOD")
        lib_client.images.build(path=context, tag="localhost:5000/allis:good")
        lib_client.images.pull('registry:2')
        hub_container = lib_client.containers.run('registry:2',
                                                  detach=True,
                                                  ports={5000: 5000})
        self.container_cleanup.append(hub_container.name)
        lib_client.images.push("localhost:5000/allis:good")
        #Let's delete the image from the local cache so that it has to be downloaded
        lib_client.images.remove("localhost:5000/allis:good")
        client = DockerClient.get_client()
        images = lib_client.images.list(name="localhost:5000/allis")
        assert len(images) == 0
        client.check_image("localhost:5000/allis:good")
        self.image_cleanup.append("localhost:5000/allis:good")
        images = lib_client.images.list(name="localhost:5000/allis")
        assert len(images) == 1
Ejemplo n.º 15
0
 def test_check_image_invalid_url(self):
     client = DockerClient.get_client()
     with pytest.raises(exceptions.DockerException):
         client.check_image(
             'somerepothatdoesntexist.org/imagename:imagetag')