class TestContainerManager_pull_image(TestCase):
    def setUp(self):
        self.image_name = "image name"

        self.mock_docker_client = Mock()
        self.mock_docker_client.api = Mock()
        self.mock_docker_client.api.pull = Mock()

        self.manager = ContainerManager(docker_client=self.mock_docker_client)

    def test_must_pull_and_print_progress_dots(self):

        stream = io.StringIO()
        pull_result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
        self.mock_docker_client.api.pull.return_value = pull_result
        expected_stream_output = "\nFetching {} Docker container image...{}\n".format(
            self.image_name, "." * len(pull_result)  # Progress bar will print one dot per response from pull API
        )

        self.manager.pull_image(self.image_name, stream=stream)

        self.mock_docker_client.api.pull.assert_called_with(self.image_name, stream=True, decode=True)
        self.assertEqual(stream.getvalue(), expected_stream_output)

    def test_must_raise_if_image_not_found(self):
        msg = "some error"
        self.mock_docker_client.api.pull.side_effect = APIError(msg)

        with self.assertRaises(DockerImagePullFailedException) as context:
            self.manager.pull_image("imagename")

        ex = context.exception
        self.assertEqual(str(ex), msg)
class TestContainerManager(TestCase):
    """
    Verifies functionality of ContainerManager by calling Docker APIs
    """
    IMAGE = "busybox"  # small sized Linux container

    @classmethod
    def setUpClass(cls):
        # Make sure we start with a clean slate
        docker_client = docker.from_env()
        TestContainerManager._remove_image(docker_client)

    def setUp(self):
        self.manager = ContainerManager()
        self.docker_client = docker.from_env()

    def tearDown(self):
        self._remove_image(self.docker_client)

    def test_pull_image(self):
        # Image should not exist
        self.assertFalse(self.manager.has_image(self.IMAGE))

        # Pull the image
        self.manager.pull_image(self.IMAGE)

        # Image should be available now
        self.assertTrue(self.manager.has_image(self.IMAGE))

    @classmethod
    def _remove_image(cls, docker_client):
        try:
            docker_client.images.remove(cls.IMAGE)
        except docker.errors.ImageNotFound:
            pass
Example #3
0
    def setUp(self):
        self.image_name = "image name"

        self.mock_docker_client = Mock()
        self.mock_docker_client.images = Mock()
        self.mock_docker_client.images.get = Mock()

        self.manager = ContainerManager(docker_client=self.mock_docker_client)
Example #4
0
    def test_must_call_delete_on_container(self):

        manager = ContainerManager()
        container = Mock()
        container.delete = Mock()

        manager.stop(container)
        container.delete.assert_called_with()
Example #5
0
    def test_must_call_delete_on_container(self):

        manager = ContainerManager()
        container = Mock()
        container.delete = Mock()

        manager.stop(container)
        container.delete.assert_called_with()
Example #6
0
    def setUp(self):
        self.mock_docker_client = Mock()
        self.manager = ContainerManager(docker_client=self.mock_docker_client)

        self.image_name = "image name"
        self.container_mock = Mock()
        self.container_mock.image = self.image_name
        self.container_mock.start = Mock()
        self.container_mock.create = Mock()
        self.container_mock.is_created = Mock()
Example #7
0
    def setUp(self):
        self.ping_mock = Mock()

        self.docker_client_mock = Mock()
        self.docker_client_mock.ping = self.ping_mock

        self.manager = ContainerManager(docker_client=self.docker_client_mock)
Example #8
0
    def __enter__(self):
        self._template_dict = get_template_data(self._template_file)

        self._function_provider = SamFunctionProvider(
            self._template_dict, self._parameter_overrides)
        self._layer_provider = SamLayerProvider(self._template_dict,
                                                self._parameter_overrides)

        if not self._base_dir:
            # Base directory, if not provided, is the directory containing the template
            self._base_dir = str(
                pathlib.Path(self._template_file).resolve().parent)

        self._build_dir = self._setup_build_dir(self._build_dir, self._clean)

        if self._cached:
            cache_path = pathlib.Path(self._cache_dir)
            cache_path.mkdir(mode=self._BUILD_DIR_PERMISSIONS,
                             parents=True,
                             exist_ok=True)
            self._cache_dir = str(cache_path.resolve())

        if self._use_container:
            self._container_manager = ContainerManager(
                docker_network_id=self._docker_network,
                skip_pull_image=self._skip_pull_image)

        return self
Example #9
0
    def test_must_invoke(self):
        input_event = '"some data"'
        expected_env_vars = {
            "var1": "override_value1",
            "var2": "shell_env_value2"
        }

        manager = ContainerManager()
        local_runtime = LambdaRuntime(manager)
        runner = LocalLambdaRunner(local_runtime, self.mock_function_provider, self.cwd, self.env_var_overrides,
                                   debug_args=None, debug_port=None, aws_profile=None)

        # Append the real AWS credentials to the expected values.
        creds = runner.get_aws_creds()
        # default value for creds is not configured by the test. But coming from a downstream class
        expected_env_vars["AWS_SECRET_ACCESS_KEY"] = creds.get("secret", "defaultsecret")
        expected_env_vars["AWS_ACCESS_KEY_ID"] = creds.get("key", "defaultkey")
        expected_env_vars["AWS_REGION"] = creds.get("region", "us-east-1")

        stdout_stream = io.BytesIO()
        stderr_stream = io.BytesIO()
        runner.invoke(self.function_name, input_event, stdout=stdout_stream, stderr=stderr_stream)

        # stderr is where the Lambda container runtime logs are available. It usually contains requestId, start time
        # etc. So it is non-zero in size
        self.assertGreater(len(stderr_stream.getvalue().strip()), 0, "stderr stream must contain data")

        # This should contain all the environment variables passed to the function
        actual_output = json.loads(stdout_stream.getvalue().strip().decode('utf-8'))

        for key, value in expected_env_vars.items():
            self.assertTrue(key in actual_output, "Key '{}' must be in function output".format(key))
            self.assertEquals(actual_output.get(key), value)
Example #10
0
    def setUp(self):
        self.image_name = "image name"

        self.mock_docker_client = Mock()
        self.mock_docker_client.images = Mock()
        self.mock_docker_client.images.get = Mock()

        self.manager = ContainerManager(docker_client=self.mock_docker_client)
Example #11
0
    def setUp(self):
        self.code_dir = {
            "echo": nodejs_lambda(ECHO_CODE),
            "sleep": nodejs_lambda(SLEEP_CODE),
            "envvar": nodejs_lambda(GET_ENV_VAR)
        }

        self.container_manager = ContainerManager()
        self.runtime = LambdaRuntime(self.container_manager)
Example #12
0
class TestContainerManager_has_image(TestCase):
    def setUp(self):
        self.image_name = "image name"

        self.mock_docker_client = Mock()
        self.mock_docker_client.images = Mock()
        self.mock_docker_client.images.get = Mock()

        self.manager = ContainerManager(docker_client=self.mock_docker_client)

    def test_must_find_an_image(self):

        self.assertTrue(self.manager.has_image(self.image_name))

    def test_must_not_find_image(self):

        self.mock_docker_client.images.get.side_effect = ImageNotFound("test")
        self.assertFalse(self.manager.has_image(self.image_name))
Example #13
0
    def setUp(self):
        self.host = "127.0.0.1"
        self.port = random.randint(30000, 40000)  # get a random port
        self.url = "http://{}:{}".format(self.host, self.port)

        self.code_abs_path = nodejs_lambda(API_GATEWAY_ECHO_EVENT)

        # Let's convert this absolute path to relative path. Let the parent be the CWD, and codeuri be the folder
        self.cwd = os.path.dirname(self.code_abs_path)
        self.code_uri = os.path.relpath(self.code_abs_path, self.cwd)  # Get relative path with respect to CWD

        # Setup a static file in the directory
        self.static_dir = "mystaticdir"
        self.static_file_name = "myfile.txt"
        self.static_file_content = "This is a static file"
        self._setup_static_file(
            os.path.join(self.cwd, self.static_dir),  # Create static directory with in cwd
            self.static_file_name,
            self.static_file_content,
        )

        # Create one Lambda function
        self.function_name = "name"
        self.function = provider.Function(
            name=self.function_name,
            runtime="nodejs4.3",
            memory=256,
            timeout=5,
            handler="index.handler",
            codeuri=self.code_uri,
            environment={},
            rolearn=None,
            layers=[],
        )
        self.mock_function_provider = Mock()
        self.mock_function_provider.get.return_value = self.function

        # Setup two APIs pointing to the same function
        routes = [
            Route(path="/get", methods=["GET"], function_name=self.function_name),
            Route(path="/post", methods=["POST"], function_name=self.function_name),
        ]
        api = Api(routes=routes)

        self.api_provider_mock = Mock()
        self.api_provider_mock.get_all.return_value = api

        # Now wire up the Lambda invoker and pass it through the context
        self.lambda_invoke_context_mock = Mock()
        manager = ContainerManager()
        layer_downloader = LayerDownloader("./", "./")
        lambda_image = LambdaImage(layer_downloader, False, False)
        local_runtime = LambdaRuntime(manager, lambda_image)
        lambda_runner = LocalLambdaRunner(local_runtime, self.mock_function_provider, self.cwd, debug_context=None)
        self.lambda_invoke_context_mock.local_lambda_runner = lambda_runner
        self.lambda_invoke_context_mock.get_cwd.return_value = self.cwd
Example #14
0
class TestContainerManager_has_image(TestCase):

    def setUp(self):
        self.image_name = "image name"

        self.mock_docker_client = Mock()
        self.mock_docker_client.images = Mock()
        self.mock_docker_client.images.get = Mock()

        self.manager = ContainerManager(docker_client=self.mock_docker_client)

    def test_must_find_an_image(self):

        self.assertTrue(self.manager.has_image(self.image_name))

    def test_must_not_find_image(self):

        self.mock_docker_client.images.get.side_effect = ImageNotFound("test")
        self.assertFalse(self.manager.has_image(self.image_name))
Example #15
0
    def setUp(self):
        self.mock_docker_client = Mock()
        self.manager = ContainerManager(docker_client=self.mock_docker_client)

        self.image_name = "image name"
        self.container_mock = Mock()
        self.container_mock.image = self.image_name
        self.container_mock.start = Mock()
        self.container_mock.create = Mock()
        self.container_mock.is_created = Mock()
Example #16
0
    def setUp(self):
        self.code_dir = {
            "echo": nodejs_lambda(ECHO_CODE),
            "sleep": nodejs_lambda(SLEEP_CODE),
            "envvar": nodejs_lambda(GET_ENV_VAR)
        }

        self.container_manager = ContainerManager()
        layer_downloader = LayerDownloader("./", "./")
        self.lambda_image = LambdaImage(layer_downloader, False, False)
        self.runtime = LambdaRuntime(self.container_manager, self.lambda_image)
Example #17
0
def make_service(function_provider, cwd):
    port = random_port()
    manager = ContainerManager()
    layer_downloader = LayerDownloader("./", "./")
    image_builder = LambdaImage(layer_downloader, False, False)
    local_runtime = LambdaRuntime(manager, image_builder)
    lambda_runner = LocalLambdaRunner(local_runtime=local_runtime, function_provider=function_provider, cwd=cwd)

    service = LocalLambdaInvokeService(lambda_runner, port=port, host="127.0.0.1")

    scheme = "http"
    url = "{}://127.0.0.1:{}".format(scheme, port)
    return service, port, url, scheme
Example #18
0
class TestContainerManager_pull_image(TestCase):

    def setUp(self):
        self.image_name = "image name"

        self.mock_docker_client = Mock()
        self.mock_docker_client.api = Mock()
        self.mock_docker_client.api.pull = Mock()

        self.manager = ContainerManager(docker_client=self.mock_docker_client)

    def test_must_pull_and_print_progress_dots(self):

        stream = io.StringIO()
        pull_result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
        self.mock_docker_client.api.pull.return_value = pull_result
        expected_stream_output = "\nFetching {} Docker container image...{}\n".format(
            self.image_name,
            '.' * len(pull_result)  # Progress bar will print one dot per response from pull API
        )

        self.manager.pull_image(self.image_name, stream=stream)

        self.mock_docker_client.api.pull.assert_called_with(self.image_name,
                                                            stream=True,
                                                            decode=True)
        self.assertEquals(stream.getvalue(), expected_stream_output)

    def test_must_raise_if_image_not_found(self):
        msg = "some error"
        self.mock_docker_client.api.pull.side_effect = APIError(msg)

        with self.assertRaises(DockerImagePullFailedException) as context:
            self.manager.pull_image("imagename")

        ex = context.exception
        self.assertEquals(str(ex), msg)
Example #19
0
def make_service(function_provider, cwd):
    port = random_port()
    manager = ContainerManager()
    local_runtime = LambdaRuntime(manager)
    lambda_runner = LocalLambdaRunner(local_runtime=local_runtime,
                                      function_provider=function_provider,
                                      cwd=cwd)

    service = LocalLambdaInvokeService(lambda_runner,
                                       port=port,
                                       host='127.0.0.1')

    scheme = "http"
    url = '{}://127.0.0.1:{}'.format(scheme, port)
    return service, port, url, scheme
Example #20
0
    def setUp(self):
        self.code_dir = nodejs_lambda(SLEEP_CODE)

        Input = namedtuple('Input', ["timeout", "sleep", "check_stdout"])
        self.inputs = [
            Input(sleep=1, timeout=10, check_stdout=True),
            Input(sleep=2, timeout=10, check_stdout=True),
            Input(sleep=3, timeout=10, check_stdout=True),
            Input(sleep=5, timeout=10, check_stdout=True),
            Input(sleep=8, timeout=10, check_stdout=True),
            Input(sleep=13, timeout=12, check_stdout=False),  # Must timeout
            Input(sleep=21, timeout=20, check_stdout=False),  # Must timeout. So stdout will be empty
        ]
        random.shuffle(self.inputs)

        container_manager = ContainerManager()
        self.runtime = LambdaRuntime(container_manager)
Example #21
0
    def _get_container_manager(docker_network, skip_pull_image):
        """
        Creates a ContainerManager with specified options

        Parameters
        ----------
        docker_network str
            Docker network identifier
        skip_pull_image bool
            Should the manager skip pulling the image

        Returns
        -------
        samcli.local.docker.manager.ContainerManager
            Object representing Docker container manager
        """

        return ContainerManager(docker_network_id=docker_network, skip_pull_image=skip_pull_image)
Example #22
0
    def setUp(self):
        self.code_dir = nodejs_lambda(SLEEP_CODE)

        Input = namedtuple("Input", ["timeout", "sleep", "check_stdout"])
        self.inputs = [
            Input(sleep=1, timeout=10, check_stdout=True),
            Input(sleep=2, timeout=10, check_stdout=True),
            Input(sleep=3, timeout=10, check_stdout=True),
            Input(sleep=5, timeout=10, check_stdout=True),
            Input(sleep=8, timeout=10, check_stdout=True),
            Input(sleep=13, timeout=12, check_stdout=False),  # Must timeout
            Input(sleep=21, timeout=20, check_stdout=False),  # Must timeout. So stdout will be empty
        ]
        random.shuffle(self.inputs)

        container_manager = ContainerManager()
        layer_downloader = LayerDownloader("./", "./")
        self.lambda_image = LambdaImage(layer_downloader, False, False)
        self.runtime = LambdaRuntime(container_manager, self.lambda_image)
Example #23
0
    def local_lambda_runner(self):
        """
        Returns an instance of the runner capable of running Lambda functions locally

        :return samcli.commands.local.lib.local_lambda.LocalLambdaRunner: Runner configured to run Lambda functions
            locally
        """

        container_manager = ContainerManager(docker_network_id=self._docker_network,
                                             skip_pull_image=self._skip_pull_image)

        lambda_runtime = LambdaRuntime(container_manager)
        return LocalLambdaRunner(local_runtime=lambda_runtime,
                                 function_provider=self._function_provider,
                                 cwd=self.get_cwd(),
                                 env_vars_values=self._env_vars_value,
                                 debug_context=self._debug_context,
                                 aws_profile=self._aws_profile,
                                 aws_region=self._aws_region)
Example #24
0
    def __enter__(self):
        self._template_dict = get_template_data(self._template_file)

        self._function_provider = SamFunctionProvider(
            self._template_dict, self._parameter_overrides)

        if not self._base_dir:
            # Base directory, if not provided, is the directory containing the template
            self._base_dir = str(
                pathlib.Path(self._template_file).resolve().parent)

        self._build_dir = self._setup_build_dir(self._build_dir, self._clean)

        if self._use_container:
            self._container_manager = ContainerManager(
                docker_network_id=self._docker_network,
                skip_pull_image=self._skip_pull_image)

        return self
Example #25
0
    def __enter__(self) -> "BuildContext":

        self._stacks, remote_stack_full_paths = SamLocalStackProvider.get_stacks(
            self._template_file, parameter_overrides=self._parameter_overrides)

        if remote_stack_full_paths:
            LOG.warning(
                "Below nested stacks(s) specify non-local URL(s), which are unsupported:\n%s\n"
                "Skipping building resources inside these nested stacks.",
                "\n".join([
                    f"- {full_path}" for full_path in remote_stack_full_paths
                ]),
            )

        # Note(xinhol): self._use_raw_codeuri is added temporarily to fix issue #2717
        # when base_dir is provided, codeuri should not be resolved based on template file path.
        # we will refactor to make all path resolution inside providers intead of in multiple places
        self._function_provider = SamFunctionProvider(self.stacks,
                                                      self._use_raw_codeuri)
        self._layer_provider = SamLayerProvider(self.stacks,
                                                self._use_raw_codeuri)

        if not self._base_dir:
            # Base directory, if not provided, is the directory containing the template
            self._base_dir = str(
                pathlib.Path(self._template_file).resolve().parent)

        self._build_dir = self._setup_build_dir(self._build_dir, self._clean)

        if self._cached:
            cache_path = pathlib.Path(self._cache_dir)
            cache_path.mkdir(mode=self._BUILD_DIR_PERMISSIONS,
                             parents=True,
                             exist_ok=True)
            self._cache_dir = str(cache_path.resolve())

        if self._use_container:
            self._container_manager = ContainerManager(
                docker_network_id=self._docker_network,
                skip_pull_image=self._skip_pull_image)

        return self
Example #26
0
    def _get_container_manager(docker_network, skip_pull_image, shutdown):
        """
        Creates a ContainerManager with specified options

        Parameters
        ----------
        docker_network str
            Docker network identifier
        skip_pull_image bool
            Should the manager skip pulling the image
        shutdown bool
            Should SHUTDOWN events be sent when tearing down image

        Returns
        -------
        samcli.local.docker.manager.ContainerManager
            Object representing Docker container manager
        """

        return ContainerManager(docker_network_id=docker_network,
                                skip_pull_image=skip_pull_image,
                                do_shutdown_event=shutdown)
Example #27
0
    def local_lambda_runner(self):
        """
        Returns an instance of the runner capable of running Lambda functions locally

        :return samcli.commands.local.lib.local_lambda.LocalLambdaRunner: Runner configured to run Lambda functions
            locally
        """

        container_manager = ContainerManager(
            docker_network_id=self._docker_network,
            skip_pull_image=self._skip_pull_image)

        layer_downloader = LayerDownloader(self._layer_cache_basedir,
                                           self.get_cwd())
        image_builder = LambdaImage(layer_downloader, self._skip_pull_image,
                                    self._force_image_build)

        lambda_runtime = LambdaRuntime(container_manager, image_builder)
        return LocalLambdaRunner(local_runtime=lambda_runtime,
                                 function_provider=self._function_provider,
                                 cwd=self.get_cwd(),
                                 env_vars_values=self._env_vars_value,
                                 debug_context=self._debug_context)
Example #28
0
class TestContainerManager_run(TestCase):

    def setUp(self):
        self.mock_docker_client = Mock()
        self.manager = ContainerManager(docker_client=self.mock_docker_client)

        self.image_name = "image name"
        self.container_mock = Mock()
        self.container_mock.image = self.image_name
        self.container_mock.start = Mock()
        self.container_mock.create = Mock()
        self.container_mock.is_created = Mock()

    def test_must_error_with_warm(self):

        with self.assertRaises(ValueError):
            self.manager.run(self.container_mock, warm=True)

    def test_must_pull_image_and_run_container(self):
        input_data = "input data"

        self.manager.has_image = Mock()
        self.manager.pull_image = Mock()

        # Assume the image doesn't exist.
        self.manager.has_image.return_value = False

        self.manager.run(self.container_mock, input_data)

        self.manager.has_image.assert_called_with(self.image_name)
        self.manager.pull_image.assert_called_with(self.image_name)
        self.container_mock.start.assert_called_with(input_data=input_data)

    def test_must_pull_image_if_image_exist_and_no_skip(self):
        input_data = "input data"

        self.manager.has_image = Mock()
        self.manager.pull_image = Mock()

        # Assume the image exist.
        self.manager.has_image.return_value = True
        # And, don't skip pulling => Pull again
        self.manager.skip_pull_image = False

        self.manager.run(self.container_mock, input_data)

        self.manager.has_image.assert_called_with(self.image_name)
        self.manager.pull_image.assert_called_with(self.image_name)
        self.container_mock.start.assert_called_with(input_data=input_data)

    def test_must_not_pull_image_if_image_is_samcli_lambda_image(self):
        input_data = "input data"

        self.manager.has_image = Mock()
        self.manager.pull_image = Mock()

        # Assume the image exist.
        self.manager.has_image.return_value = True
        # And, don't skip pulling => Pull again
        self.manager.skip_pull_image = False

        self.container_mock.image = "samcli/lambda"

        self.manager.run(self.container_mock, input_data)

        self.manager.has_image.assert_called_with("samcli/lambda")
        self.manager.pull_image.assert_not_called()
        self.container_mock.start.assert_called_with(input_data=input_data)

    def test_must_not_pull_image_if_asked_to_skip(self):
        input_data = "input data"

        self.manager.has_image = Mock()
        self.manager.pull_image = Mock()

        # Assume the image exist.
        self.manager.has_image.return_value = True
        # And, skip pulling
        self.manager.skip_pull_image = True

        self.manager.run(self.container_mock, input_data)

        self.manager.has_image.assert_called_with(self.image_name)
        # Must not call pull_image
        self.manager.pull_image.assert_not_called()
        self.container_mock.start.assert_called_with(input_data=input_data)

    def test_must_fail_if_image_pull_failed_and_image_does_not_exist(self):
        input_data = "input data"

        self.manager.has_image = Mock()
        self.manager.pull_image = Mock(side_effect=DockerImagePullFailedException("Failed to pull image"))

        # Assume the image exist.
        self.manager.has_image.return_value = False
        # And, don't skip pulling => Pull again
        self.manager.skip_pull_image = False

        with self.assertRaises(DockerImagePullFailedException):
            self.manager.run(self.container_mock, input_data)

        self.manager.has_image.assert_called_with(self.image_name)
        self.manager.pull_image.assert_called_with(self.image_name)
        self.container_mock.start.assert_not_called()

    def test_must_run_if_image_pull_failed_and_image_does_exist(self):
        input_data = "input data"

        self.manager.has_image = Mock()
        self.manager.pull_image = Mock(side_effect=DockerImagePullFailedException("Failed to pull image"))

        # Assume the image exist.
        self.manager.has_image.return_value = True
        # And, don't skip pulling => Pull again
        self.manager.skip_pull_image = False

        self.manager.run(self.container_mock, input_data)

        self.manager.has_image.assert_called_with(self.image_name)
        self.manager.pull_image.assert_called_with(self.image_name)
        self.container_mock.start.assert_called_with(input_data=input_data)

    def test_must_create_container_if_not_exists(self):
        input_data = "input data"
        self.manager.has_image = Mock()
        self.manager.pull_image = Mock()

        # Assume container does NOT exist
        self.container_mock.is_created.return_value = False

        self.manager.run(self.container_mock, input_data)

        # Container should be created
        self.container_mock.create.assert_called_with()

    def test_must_not_create_container_if_it_already_exists(self):
        input_data = "input data"
        self.manager.has_image = Mock()
        self.manager.pull_image = Mock()

        # Assume container does NOT exist
        self.container_mock.is_created.return_value = True

        self.manager.run(self.container_mock, input_data)

        # Container should be created
        self.container_mock.create.assert_not_called()
Example #29
0
class TestContainerManager_run(TestCase):
    def setUp(self):
        self.mock_docker_client = Mock()
        self.manager = ContainerManager(docker_client=self.mock_docker_client)

        self.image_name = "image name"
        self.container_mock = Mock()
        self.container_mock.image = self.image_name
        self.container_mock.start = Mock()
        self.container_mock.create = Mock()
        self.container_mock.is_created = Mock()

    def test_must_error_with_warm(self):

        with self.assertRaises(ValueError):
            self.manager.run(self.container_mock, warm=True)

    def test_must_pull_image_and_run_container(self):
        input_data = "input data"

        self.manager.has_image = Mock()
        self.manager.pull_image = Mock()

        # Assume the image doesn't exist.
        self.manager.has_image.return_value = False

        self.manager.run(self.container_mock, input_data)

        self.manager.has_image.assert_called_with(self.image_name)
        self.manager.pull_image.assert_called_with(self.image_name)
        self.container_mock.start.assert_called_with(input_data=input_data)

    def test_must_pull_image_if_image_exist_and_no_skip(self):
        input_data = "input data"

        self.manager.has_image = Mock()
        self.manager.pull_image = Mock()

        # Assume the image exist.
        self.manager.has_image.return_value = True
        # And, don't skip pulling => Pull again
        self.manager.skip_pull_image = False

        self.manager.run(self.container_mock, input_data)

        self.manager.has_image.assert_called_with(self.image_name)
        self.manager.pull_image.assert_called_with(self.image_name)
        self.container_mock.start.assert_called_with(input_data=input_data)

    def test_must_not_pull_image_if_asked_to_skip(self):
        input_data = "input data"

        self.manager.has_image = Mock()
        self.manager.pull_image = Mock()

        # Assume the image exist.
        self.manager.has_image.return_value = True
        # And, skip pulling
        self.manager.skip_pull_image = True

        self.manager.run(self.container_mock, input_data)

        self.manager.has_image.assert_called_with(self.image_name)
        # Must not call pull_image
        self.manager.pull_image.assert_not_called()
        self.container_mock.start.assert_called_with(input_data=input_data)

    def test_must_create_container_if_not_exists(self):
        input_data = "input data"
        self.manager.has_image = Mock()
        self.manager.pull_image = Mock()

        # Assume container does NOT exist
        self.container_mock.is_created.return_value = False

        self.manager.run(self.container_mock, input_data)

        # Container should be created
        self.container_mock.create.assert_called_with()

    def test_must_not_create_container_if_it_already_exists(self):
        input_data = "input data"
        self.manager.has_image = Mock()
        self.manager.pull_image = Mock()

        # Assume container does NOT exist
        self.container_mock.is_created.return_value = True

        self.manager.run(self.container_mock, input_data)

        # Container should be created
        self.container_mock.create.assert_not_called()
Example #30
0
 def setUp(self):
     self.manager = ContainerManager()
     self.docker_client = docker.from_env()
Example #31
0
    def test_must_initialize_with_default_value(self):

        manager = ContainerManager()
        self.assertFalse(manager.skip_pull_image)
    def setUpClass(cls):

        manager = ContainerManager()
        if not manager.has_image(cls.IMAGE_NAME):
            manager.pull_image(cls.IMAGE_NAME)
Example #33
0
class TestContainerManager_pull_image(TestCase):
    def setUp(self):
        self.image_name = "image name"

        self.mock_docker_client = Mock()
        self.mock_docker_client.api = Mock()
        self.mock_docker_client.api.pull = Mock()

        self.manager = ContainerManager(docker_client=self.mock_docker_client)

    def test_must_pull_and_print_progress_dots(self):

        stream = io.StringIO()
        pull_result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
        self.mock_docker_client.api.pull.return_value = pull_result
        expected_stream_output = "\nFetching {} Docker container image...{}\n".format(
            self.image_name,
            "." *
            len(pull_result
                )  # Progress bar will print one dot per response from pull API
        )

        self.manager.pull_image(self.image_name, stream=stream)

        self.mock_docker_client.api.pull.assert_called_with(self.image_name,
                                                            stream=True,
                                                            decode=True)
        self.assertEqual(stream.getvalue(), expected_stream_output)

    def test_must_raise_if_image_not_found(self):
        msg = "some error"
        self.mock_docker_client.api.pull.side_effect = APIError(msg)

        with self.assertRaises(DockerImagePullFailedException) as context:
            self.manager.pull_image("imagename")

        ex = context.exception
        self.assertEqual(str(ex), msg)

    @patch("samcli.local.docker.manager.threading")
    def test_multiple_image_pulls_must_use_locks(self, mock_threading):
        self.mock_docker_client.api.pull.return_value = [1, 2, 3]

        # mock general lock
        mock_lock = MagicMock()
        self.manager._lock = mock_lock

        # mock locks per image
        mock_image1_lock = MagicMock()
        mock_image2_lock = MagicMock()
        mock_threading.Lock.side_effect = [mock_image1_lock, mock_image2_lock]

        # pull 2 different images for multiple times
        self.manager.pull_image("image1")
        self.manager.pull_image("image1")
        self.manager.pull_image("image2")

        # assert that image1 lock have been used twice and image2 lock only used once
        mock_image1_lock.assert_has_calls(
            2 *
            [call.__enter__(), call.__exit__(ANY, ANY, ANY)],
            any_order=True)
        mock_image2_lock.assert_has_calls(
            [call.__enter__(), call.__exit__(ANY, ANY, ANY)])

        # assert that general lock have been used three times for all the image pulls
        mock_lock.assert_has_calls(
            3 *
            [call.__enter__(), call.__exit__(ANY, ANY, ANY)],
            any_order=True)
Example #34
0
class TestContainerManager_run(TestCase):
    def setUp(self):
        self.mock_docker_client = Mock()
        self.manager = ContainerManager(docker_client=self.mock_docker_client)

        self.image_name = "image name"
        self.container_mock = Mock()
        self.container_mock.image = self.image_name
        self.container_mock.start = Mock()
        self.container_mock.create = Mock()
        self.container_mock.is_created = Mock()

    def test_must_error_with_warm(self):

        with self.assertRaises(ValueError):
            self.manager.run(self.container_mock, warm=True)

    def test_must_pull_image_and_run_container(self):
        input_data = "input data"

        self.manager.has_image = Mock()
        self.manager.pull_image = Mock()

        # Assume the image doesn't exist.
        self.manager.has_image.return_value = False

        self.manager.run(self.container_mock, input_data)

        self.manager.has_image.assert_called_with(self.image_name)
        self.manager.pull_image.assert_called_with(self.image_name)
        self.container_mock.start.assert_called_with(input_data=input_data)

    def test_must_pull_image_if_image_exist_and_no_skip(self):
        input_data = "input data"

        self.manager.has_image = Mock()
        self.manager.pull_image = Mock()

        # Assume the image exist.
        self.manager.has_image.return_value = True
        # And, don't skip pulling => Pull again
        self.manager.skip_pull_image = False

        self.manager.run(self.container_mock, input_data)

        self.manager.has_image.assert_called_with(self.image_name)
        self.manager.pull_image.assert_called_with(self.image_name)
        self.container_mock.start.assert_called_with(input_data=input_data)

    def test_must_not_pull_image_if_image_is_samcli_lambda_image(self):
        input_data = "input data"

        self.manager.has_image = Mock()
        self.manager.pull_image = Mock()

        # Assume the image exist.
        self.manager.has_image.return_value = True
        # And, don't skip pulling => Pull again
        self.manager.skip_pull_image = False

        self.container_mock.image = "samcli/lambda"

        self.manager.run(self.container_mock, input_data)

        self.manager.has_image.assert_called_with("samcli/lambda")
        self.manager.pull_image.assert_not_called()
        self.container_mock.start.assert_called_with(input_data=input_data)

    def test_must_not_pull_image_if_image_is_rapid_image(self):
        input_data = "input data"
        rapid_image_name = "Mock_image_name:rapid-1.0.0"

        self.manager.has_image = Mock()
        self.manager.pull_image = Mock()

        # Assume the image exist.
        self.manager.has_image.return_value = True
        # And, don't skip pulling => Pull again
        self.manager.skip_pull_image = False

        self.container_mock.image = rapid_image_name

        self.manager.run(self.container_mock, input_data)

        self.manager.has_image.assert_called_with(rapid_image_name)
        self.manager.pull_image.assert_not_called()
        self.container_mock.start.assert_called_with(input_data=input_data)

    def test_must_not_pull_image_if_asked_to_skip(self):
        input_data = "input data"

        self.manager.has_image = Mock()
        self.manager.pull_image = Mock()

        # Assume the image exist.
        self.manager.has_image.return_value = True
        # And, skip pulling
        self.manager.skip_pull_image = True

        self.manager.run(self.container_mock, input_data)

        self.manager.has_image.assert_called_with(self.image_name)
        # Must not call pull_image
        self.manager.pull_image.assert_not_called()
        self.container_mock.start.assert_called_with(input_data=input_data)

    def test_must_fail_if_image_pull_failed_and_image_does_not_exist(self):
        input_data = "input data"

        self.manager.has_image = Mock()
        self.manager.pull_image = Mock(
            side_effect=DockerImagePullFailedException("Failed to pull image"))

        # Assume the image exist.
        self.manager.has_image.return_value = False
        # And, don't skip pulling => Pull again
        self.manager.skip_pull_image = False

        with self.assertRaises(DockerImagePullFailedException):
            self.manager.run(self.container_mock, input_data)

        self.manager.has_image.assert_called_with(self.image_name)
        self.manager.pull_image.assert_called_with(self.image_name)
        self.container_mock.start.assert_not_called()

    def test_must_run_if_image_pull_failed_and_image_does_exist(self):
        input_data = "input data"

        self.manager.has_image = Mock()
        self.manager.pull_image = Mock(
            side_effect=DockerImagePullFailedException("Failed to pull image"))

        # Assume the image exist.
        self.manager.has_image.return_value = True
        # And, don't skip pulling => Pull again
        self.manager.skip_pull_image = False

        self.manager.run(self.container_mock, input_data)

        self.manager.has_image.assert_called_with(self.image_name)
        self.manager.pull_image.assert_called_with(self.image_name)
        self.container_mock.start.assert_called_with(input_data=input_data)

    def test_must_create_container_if_not_exists(self):
        input_data = "input data"
        self.manager.has_image = Mock()
        self.manager.pull_image = Mock()

        # Assume container does NOT exist
        self.container_mock.is_created.return_value = False

        self.manager.run(self.container_mock, input_data)

        # Container should be created
        self.container_mock.create.assert_called_with()

    def test_must_not_create_container_if_it_already_exists(self):
        input_data = "input data"
        self.manager.has_image = Mock()
        self.manager.pull_image = Mock()

        # Assume container does NOT exist
        self.container_mock.is_created.return_value = True

        self.manager.run(self.container_mock, input_data)

        # Container should be created
        self.container_mock.create.assert_not_called()
    def setUpClass(cls):

        manager = ContainerManager()
        if not manager.has_image(cls.IMAGE_NAME):
            manager.pull_image(cls.IMAGE_NAME)
 def setUp(self):
     self.manager = ContainerManager()
     self.docker_client = docker.from_env()