def _get_latest_docker_status(self):
        """
        Synchronise local Django Container models with remote Docker containers
        """
        ps = get_docker_ps.delay()

        containers_docker = None
        try:
            containers_docker = ps.get(timeout=30)
        except celery.exceptions.TimeoutError as e:
            logging.exception("get_docker_ps timed out (30 seconds)")

        if containers_docker is None:
            # Apparently something is wrong with the remote docker or celery
            # To prevent new task creation by Containers exit beat.
            return

        docker_dict = {x['Id']: x for x in containers_docker}
        docker_set = set(docker_dict.keys())

        # retrieve container from database
        container_set = set(
            Container.objects.values_list('docker_id', flat=True))

        # Work out matching matrix
        #       docker  yes non
        # model x
        # yes           1_1 1_0
        # no            0_1 0_0
        #
        m_1_1 = container_set & docker_set
        m_1_0 = container_set - docker_set
        m_0_1 = docker_set - container_set
        m_0_0 = ((docker_set | container_set) -
                 (docker_set ^ container_set) -
                 (docker_set & container_set)
                 )

        # Update state of all matching containers
        container_match = m_1_1 | m_1_0
        for con_id in container_match:
            snapshot = docker_dict[
                con_id] if con_id in docker_dict else None
            for c in Container.objects.filter(docker_id=con_id):
                c.update_from_docker_snapshot(snapshot)

        # Call error for mismatch
        container_mismatch = m_0_1 | m_0_0
        for container in container_mismatch:
            info = docker_dict[container]
            if ('Config' in info and
                'Labels' in info['Config'] and
                    'type' in info['Config']['Labels']):
                type = info['Config']['Labels']['type']
                if type in [choice[0] for choice in Container.CONTAINER_TYPE_CHOICES]:
                    self.stderr.write(
                        "Docker container {} not found in database!".format(container))
                    do_docker_remove.delay(container, force=True)
            else:
                logging.info("Found non-delft3dgt docker container, ignoring.")
 def test_do_docker_remove(self, mockClient):
     """
     Assert that the docker_remove task
     calls the docker client.remove_container() function
     """
     delay = do_docker_remove.delay("id")
     mockClient.return_value.remove_container.assert_called_with(
         container="id", force=False)
     container, log = delay.result
     self.assertEqual(container, "id")
     self.assertEqual(log, "")
Example #3
0
 def test_do_docker_remove(self, mockClient):
     """
     Assert that the docker_remove task
     calls the docker client.remove_container() function
     """
     delay = do_docker_remove.delay("id")
     mockClient.return_value.remove_container.assert_called_with(
         container="id", force=False)
     container, log = delay.result
     self.assertEqual(container, "id")
     self.assertEqual(log, "")
Example #4
0
    def _get_latest_docker_status(self):
        """
        Synchronise local Django Container models with remote Docker containers
        """

        ps = get_docker_ps.apply_async(queue='priority')

        # Wait until the task finished successfully
        # or return if waiting too long
        checked = 0
        while not ps.successful():
            sleep(1)

            # if things take too long, revoke the task and return
            checked += 1
            if checked >= 30:
                ps.revoke()
                return False

        # task is succesful, so we're getting the result and create a set
        containers_docker = ps.result
        docker_dict = {x['Id']: x for x in containers_docker}
        docker_set = set(docker_dict.keys())

        # retrieve container from database
        container_set = set(
            Container.objects.exclude(docker_id__exact='').values_list(
                'docker_id', flat=True))

        # Work out matching matrix
        #       docker  yes no
        # model x
        # yes           1_1 1_0
        # no            0_1 0_0
        #
        m_1_1 = container_set & docker_set
        m_1_0 = container_set - docker_set
        m_0_1 = docker_set - container_set
        m_0_0 = ((docker_set | container_set) - (docker_set ^ container_set) -
                 (docker_set & container_set))

        # Update state of all matching containers
        container_match = m_1_1 | m_1_0
        for con_id in container_match:
            snapshot = docker_dict[con_id] if con_id in docker_dict else None
            for c in Container.objects.filter(docker_id=con_id):
                c.update_from_docker_snapshot(snapshot)

        # Call error for mismatch
        container_mismatch = m_0_1 | m_0_0
        for container in container_mismatch:
            info = docker_dict[container]
            if ('Config' in info and 'Labels' in info['Config']
                    and 'type' in info['Config']['Labels']):
                type = info['Config']['Labels']['type']

                choices = Container.CONTAINER_TYPE_CHOICES
                if type in [choice[0] for choice in choices]:
                    msg = "Docker container {} not found in database!".format(
                        container)
                    self.stderr.write(msg)
                    do_docker_remove.delay(container, force=True)
            else:
                logging.info("Found non-delft3dgt docker container, ignoring.")

        return True  # successful