예제 #1
0
    def test_compilation_error_dotnet(self):
        stack_name = stack_namer(compilation_error_project)
        project_dir = test_path("errors", compilation_error_project, "dotnet")
        stack = create_stack(stack_name, work_dir=project_dir)

        try:
            self.assertRaises(CompilationError, stack.up)
            self.assertRaisesRegex(CompilationError, "Build FAILED.", stack.up)
        finally:
            stack.workspace.remove_stack(stack_name)
예제 #2
0
 def test_project_settings_respected(self):
     project_name = "correct_project"
     stack_name = stack_namer(project_name)
     stack = create_stack(stack_name,
                          program=pulumi_program,
                          project_name=project_name,
                          opts=LocalWorkspaceOptions(work_dir=test_path("data", project_name)))
     project_settings = stack.workspace.project_settings()
     self.assertEqual(project_settings.description, "This is a description")
     stack.workspace.remove_stack(stack_name)
예제 #3
0
    def test_compilation_error_go(self):
        stack_name = stack_namer(compilation_error_project)
        project_dir = test_path("errors", compilation_error_project, "go")
        stack = create_stack(stack_name, work_dir=project_dir)

        try:
            self.assertRaises(CompilationError, stack.up)
            self.assertRaisesRegex(CompilationError,
                                   ": syntax error:|: undefined:", stack.up)
        finally:
            stack.workspace.remove_stack(stack_name)
예제 #4
0
    def test_structured_events(self):
        project_name = "structured_events"
        stack_name = stack_namer(project_name)
        stack = create_stack(stack_name,
                             program=pulumi_program,
                             project_name=project_name)

        stack_config: ConfigMap = {
            "bar": ConfigValue(value="abc"),
            "buzz": ConfigValue(value="secret", secret=True)
        }

        try:
            stack.set_all_config(stack_config)

            # can't mutate a bool from the callback, so use a single-item list
            seen_summary_event = [False]

            def find_summary_event(event: EngineEvent):
                if event.summary_event:
                    seen_summary_event[0] = True

            # pulumi up
            up_res = stack.up(on_event=find_summary_event)
            self.assertEqual(seen_summary_event[0], True,
                             "No SummaryEvent for `up`")
            self.assertEqual(up_res.summary.kind, "update")
            self.assertEqual(up_res.summary.result, "succeeded")

            # pulumi preview
            seen_summary_event[0] = False
            pre_res = stack.preview(on_event=find_summary_event)
            self.assertEqual(seen_summary_event[0], True,
                             "No SummaryEvent for `preview`")
            self.assertEqual(pre_res.change_summary.get(OpType.SAME), 1)

            # pulumi refresh
            seen_summary_event[0] = False
            refresh_res = stack.refresh(on_event=find_summary_event)
            self.assertEqual(seen_summary_event[0], True,
                             "No SummaryEvent for `refresh`")
            self.assertEqual(refresh_res.summary.kind, "refresh")
            self.assertEqual(refresh_res.summary.result, "succeeded")

            # pulumi destroy
            seen_summary_event[0] = False
            destroy_res = stack.destroy(on_event=find_summary_event)
            self.assertEqual(seen_summary_event[0], True,
                             "No SummaryEvent for `destroy`")
            self.assertEqual(destroy_res.summary.kind, "destroy")
            self.assertEqual(destroy_res.summary.result, "succeeded")
        finally:
            stack.workspace.remove_stack(stack_name)
예제 #5
0
    def test_compilation_error_typescript(self):
        stack_name = stack_namer(compilation_error_project)
        project_dir = test_path("errors", compilation_error_project,
                                "typescript")
        subprocess.run(["npm", "install"],
                       check=True,
                       cwd=project_dir,
                       capture_output=True)
        stack = create_stack(stack_name, work_dir=project_dir)

        try:
            self.assertRaises(CompilationError, stack.up)
            self.assertRaisesRegex(CompilationError,
                                   "Unable to compile TypeScript", stack.up)
        finally:
            stack.workspace.remove_stack(stack_name)
예제 #6
0
    def test_inline_runtime_error_python(self):
        project_name = "inline_runtime_error_python"
        stack_name = stack_namer(project_name)
        stack = create_stack(stack_name,
                             program=failing_program,
                             project_name=project_name)
        inline_error_text = "python inline source runtime error"

        try:
            self.assertRaises(InlineSourceRuntimeError, stack.up)
            self.assertRaisesRegex(InlineSourceRuntimeError, inline_error_text,
                                   stack.up)
            self.assertRaises(InlineSourceRuntimeError, stack.preview)
            self.assertRaisesRegex(InlineSourceRuntimeError, inline_error_text,
                                   stack.preview)
        finally:
            stack.workspace.remove_stack(stack_name)
예제 #7
0
    def test_supports_stack_outputs(self):
        project_name = "inline_python"
        stack_name = stack_namer(project_name)
        stack = create_stack(stack_name,
                             program=pulumi_program,
                             project_name=project_name)

        stack_config: ConfigMap = {
            "bar": ConfigValue(value="abc"),
            "buzz": ConfigValue(value="secret", secret=True)
        }

        def assert_outputs(outputs):
            self.assertEqual(len(outputs), 3)
            self.assertEqual(outputs["exp_static"].value, "foo")
            self.assertFalse(outputs["exp_static"].secret)
            self.assertEqual(outputs["exp_cfg"].value, "abc")
            self.assertFalse(outputs["exp_cfg"].secret)
            self.assertEqual(outputs["exp_secret"].value, "secret")
            self.assertTrue(outputs["exp_secret"].secret)

        try:
            stack.set_all_config(stack_config)

            initial_outputs = stack.outputs()
            self.assertEqual(len(initial_outputs), 0)

            # pulumi up
            up_res = stack.up()
            self.assertEqual(up_res.summary.kind, "update")
            self.assertEqual(up_res.summary.result, "succeeded")
            assert_outputs(up_res.outputs)

            outputs_after_up = stack.outputs()
            assert_outputs(outputs_after_up)

            # pulumi destroy
            destroy_res = stack.destroy()
            self.assertEqual(destroy_res.summary.kind, "destroy")
            self.assertEqual(destroy_res.summary.result, "succeeded")

            outputs_after_destroy = stack.outputs()
            self.assertEqual(len(outputs_after_destroy), 0)
        finally:
            stack.workspace.remove_stack(stack_name)
예제 #8
0
    def test_stack_lifecycle_inline_program(self):
        project_name = "inline_python"
        stack_name = stack_namer(project_name)
        stack = create_stack(stack_name,
                             program=pulumi_program,
                             project_name=project_name)

        stack_config: ConfigMap = {
            "bar": ConfigValue(value="abc"),
            "buzz": ConfigValue(value="secret", secret=True)
        }

        try:
            stack.set_all_config(stack_config)

            # pulumi up
            up_res = stack.up()
            self.assertEqual(len(up_res.outputs), 3)
            self.assertEqual(up_res.outputs["exp_static"].value, "foo")
            self.assertFalse(up_res.outputs["exp_static"].secret)
            self.assertEqual(up_res.outputs["exp_cfg"].value, "abc")
            self.assertFalse(up_res.outputs["exp_cfg"].secret)
            self.assertEqual(up_res.outputs["exp_secret"].value, "secret")
            self.assertTrue(up_res.outputs["exp_secret"].secret)
            self.assertEqual(up_res.summary.kind, "update")
            self.assertEqual(up_res.summary.result, "succeeded")

            # pulumi preview
            preview_result = stack.preview()
            self.assertEqual(preview_result.change_summary.get(OpType.SAME), 1)

            # pulumi refresh
            refresh_res = stack.refresh()
            self.assertEqual(refresh_res.summary.kind, "refresh")
            self.assertEqual(refresh_res.summary.result, "succeeded")

            # pulumi destroy
            destroy_res = stack.destroy()
            self.assertEqual(destroy_res.summary.kind, "destroy")
            self.assertEqual(destroy_res.summary.result, "succeeded")
        finally:
            stack.workspace.remove_stack(stack_name)
예제 #9
0
def check_isolation(minimal=False):
    stack_name = f'isolation-test-{uuid.uuid4()}'

    stack = automation.create_stack(stack_name=stack_name,
                                    project_name='isolation-test',
                                    program=program)

    with pytest.raises(automation.errors.CommandError):
        stack.set_config('bad', automation.ConfigValue('1'))
        stack.up(on_output=ignore)

    if not minimal:
        stack.set_config('bad', automation.ConfigValue('0'))
        stack.up(on_output=ignore)

    destroy_res = stack.destroy()
    assert destroy_res.summary.kind == "destroy"
    assert destroy_res.summary.result == "succeeded"

    stack.workspace.remove_stack(stack_name)
예제 #10
0
def create_handler():
    """creates new sites"""
    stack_name = request.json.get('id')
    content = request.json.get('content')
    try:

        def pulumi_program():
            return create_pulumi_program(content)

        # create a new stack, generating our pulumi program on the fly from the POST body
        stack = auto.create_stack(stack_name=stack_name,
                                  project_name=project_name,
                                  program=pulumi_program)
        stack.set_config("aws:region", auto.ConfigValue("us-west-2"))
        # deploy the stack, tailing the logs to stdout
        up_res = stack.up(on_output=print)
        return jsonify(id=stack_name, url=up_res.outputs['website_url'].value)
    except auto.StackAlreadyExistsError:
        return make_response(f"stack '{stack_name}' already exists", 409)
    except Exception as exn:
        return make_response(str(exn), 500)
예제 #11
0
async def test_parallel_updates():
    first_stack_name = f"stack-{uuid.uuid4()}"
    second_stack_name = f"stack-{uuid.uuid4()}"
    stacks = [
        automation.create_stack(stack_name,
                                project_name='test-parallel',
                                program=program)
        for stack_name in {first_stack_name, second_stack_name}
    ]
    stack_up_responses = await asyncio.gather(
        *[async_stack_up(stack) for stack in stacks])
    assert all({
        stack_response.summary.result == "succeeded"
        for stack_response in stack_up_responses
    })
    stack_destroy_responses = await asyncio.gather(
        *[async_stack_destroy(stack) for stack in stacks])
    assert all({
        stack_response.summary.result == "succeeded"
        for stack_response in stack_destroy_responses
    })
예제 #12
0
    def test_stack_lifecycle_local_program(self):
        project_name = "testproj"
        stack_name = stack_namer(project_name)
        work_dir = test_path("data", project_name)
        stack = create_stack(stack_name, work_dir=work_dir)
        self.assertIsNone(print(stack))

        config: ConfigMap = {
            "bar": ConfigValue(value="abc"),
            "buzz": ConfigValue(value="secret", secret=True)
        }
        stack.set_all_config(config)

        # pulumi up
        up_res = stack.up()
        self.assertEqual(len(up_res.outputs), 3)
        self.assertEqual(up_res.outputs["exp_static"].value, "foo")
        self.assertFalse(up_res.outputs["exp_static"].secret)
        self.assertEqual(up_res.outputs["exp_cfg"].value, "abc")
        self.assertFalse(up_res.outputs["exp_cfg"].secret)
        self.assertEqual(up_res.outputs["exp_secret"].value, "secret")
        self.assertTrue(up_res.outputs["exp_secret"].secret)
        self.assertEqual(up_res.summary.kind, "update")
        self.assertEqual(up_res.summary.result, "succeeded")

        # pulumi preview
        preview_result = stack.preview()
        self.assertEqual(preview_result.change_summary.get(OpType.SAME), 1)

        # pulumi refresh
        refresh_res = stack.refresh()
        self.assertEqual(refresh_res.summary.kind, "refresh")
        self.assertEqual(refresh_res.summary.result, "succeeded")

        # pulumi destroy
        destroy_res = stack.destroy()
        self.assertEqual(destroy_res.summary.kind, "destroy")
        self.assertEqual(destroy_res.summary.result, "succeeded")

        stack.workspace.remove_stack(stack_name)
예제 #13
0
    def test_runtime_errors(self):
        for lang in ["python", "go", "dotnet", "javascript", "typescript"]:
            stack_name = stack_namer(runtime_error_project)
            project_dir = test_path("errors", runtime_error_project, lang)

            if lang in ["javascript", "typescript"]:
                subprocess.run(["npm", "install"],
                               check=True,
                               cwd=project_dir,
                               capture_output=True)
            if lang == "python":
                subprocess.run(["python3", "-m", "venv", "venv"],
                               check=True,
                               cwd=project_dir,
                               capture_output=True)
                subprocess.run([
                    os.path.join("venv", "bin", "pip"), "install", "-r",
                    "requirements.txt"
                ],
                               check=True,
                               cwd=project_dir,
                               capture_output=True)

            stack = create_stack(stack_name, work_dir=project_dir)

            try:
                self.assertRaises(RuntimeError, stack.up)
                if lang == "go":
                    self.assertRaisesRegex(RuntimeError,
                                           "panic: runtime error", stack.up)
                else:
                    self.assertRaisesRegex(
                        RuntimeError, "failed with an unhandled exception",
                        stack.up)
            finally:
                stack.workspace.remove_stack(stack_name)
예제 #14
0
    def test_secret_config_warnings(self):
        def program():
            config = Config()

            config.get("plainstr1")
            config.require("plainstr2")
            config.get_secret("plainstr3")
            config.require_secret("plainstr4")

            config.get_bool("plainbool1")
            config.require_bool("plainbool2")
            config.get_secret_bool("plainbool3")
            config.require_secret_bool("plainbool4")

            config.get_int("plainint1")
            config.require_int("plainint2")
            config.get_secret_int("plainint3")
            config.require_secret_int("plainint4")

            config.get_float("plainfloat1")
            config.require_float("plainfloat2")
            config.get_secret_float("plainfloat3")
            config.require_secret_float("plainfloat4")

            config.get_object("plainobj1")
            config.require_object("plainobj2")
            config.get_secret_object("plainobj3")
            config.require_secret_object("plainobj4")

            config.get("str1")
            config.require("str2")
            config.get_secret("str3")
            config.require_secret("str4")

            config.get_bool("bool1")
            config.require_bool("bool2")
            config.get_secret_bool("bool3")
            config.require_secret_bool("bool4")

            config.get_int("int1")
            config.require_int("int2")
            config.get_secret_int("int3")
            config.require_secret_int("int4")

            config.get_float("float1")
            config.require_float("float2")
            config.get_secret_float("float3")
            config.require_secret_float("float4")

            config.get_object("obj1")
            config.require_object("obj2")
            config.get_secret_object("obj3")
            config.require_secret_object("obj4")

        project_name = "inline_python"
        stack_name = stack_namer(project_name)
        stack = create_stack(stack_name,
                             program=program,
                             project_name=project_name)

        stack_config: ConfigMap = {
            "plainstr1": ConfigValue(value="1"),
            "plainstr2": ConfigValue(value="2"),
            "plainstr3": ConfigValue(value="3"),
            "plainstr4": ConfigValue(value="4"),
            "plainbool1": ConfigValue(value="true"),
            "plainbool2": ConfigValue(value="true"),
            "plainbool3": ConfigValue(value="true"),
            "plainbool4": ConfigValue(value="true"),
            "plainint1": ConfigValue(value="1"),
            "plainint2": ConfigValue(value="2"),
            "plainint3": ConfigValue(value="3"),
            "plainint4": ConfigValue(value="4"),
            "plainfloat1": ConfigValue(value="1.1"),
            "plainfloat2": ConfigValue(value="2.2"),
            "plainfloat3": ConfigValue(value="3.3"),
            "plainfloat4": ConfigValue(value="4.3"),
            "plainobj1": ConfigValue(value="{}"),
            "plainobj2": ConfigValue(value="{}"),
            "plainobj3": ConfigValue(value="{}"),
            "plainobj4": ConfigValue(value="{}"),
            "str1": ConfigValue(value="1", secret=True),
            "str2": ConfigValue(value="2", secret=True),
            "str3": ConfigValue(value="3", secret=True),
            "str4": ConfigValue(value="4", secret=True),
            "bool1": ConfigValue(value="true", secret=True),
            "bool2": ConfigValue(value="true", secret=True),
            "bool3": ConfigValue(value="true", secret=True),
            "bool4": ConfigValue(value="true", secret=True),
            "int1": ConfigValue(value="1", secret=True),
            "int2": ConfigValue(value="2", secret=True),
            "int3": ConfigValue(value="3", secret=True),
            "int4": ConfigValue(value="4", secret=True),
            "float1": ConfigValue(value="1.1", secret=True),
            "float2": ConfigValue(value="2.2", secret=True),
            "float3": ConfigValue(value="3.3", secret=True),
            "float4": ConfigValue(value="4.4", secret=True),
            "obj1": ConfigValue(value="{}", secret=True),
            "obj2": ConfigValue(value="{}", secret=True),
            "obj3": ConfigValue(value="{}", secret=True),
            "obj4": ConfigValue(value="{}", secret=True),
        }

        try:
            stack.set_all_config(stack_config)

            events: List[str] = []

            def find_diagnostic_events(event: EngineEvent):
                if event.diagnostic_event and event.diagnostic_event.severity == "warning":
                    events.append(event.diagnostic_event.message)

            expected_warnings = [
                "Configuration 'inline_python:str1' value is a secret; use `get_secret` instead of `get`",
                "Configuration 'inline_python:str2' value is a secret; use `require_secret` instead of `require`",
                "Configuration 'inline_python:bool1' value is a secret; use `get_secret_bool` instead of `get_bool`",
                "Configuration 'inline_python:bool2' value is a secret; use `require_secret_bool` instead of `require_bool`",
                "Configuration 'inline_python:int1' value is a secret; use `get_secret_int` instead of `get_int`",
                "Configuration 'inline_python:int2' value is a secret; use `require_secret_int` instead of `require_int`",
                "Configuration 'inline_python:float1' value is a secret; use `get_secret_float` instead of `get_float`",
                "Configuration 'inline_python:float2' value is a secret; use `require_secret_float` instead of `require_float`",
                "Configuration 'inline_python:obj1' value is a secret; use `get_secret_object` instead of `get_object`",
                "Configuration 'inline_python:obj2' value is a secret; use `require_secret_object` instead of `require_object`",
            ]

            # These keys should not be in any warning messages.
            unexpected_warnings = [
                "plainstr1",
                "plainstr2",
                "plainstr3",
                "plainstr4",
                "plainbool1",
                "plainbool2",
                "plainbool3",
                "plainbool4",
                "plainint1",
                "plainint2",
                "plainint3",
                "plainint4",
                "plainfloat1",
                "plainfloat2",
                "plainfloat3",
                "plainfloat4",
                "plainobj1",
                "plainobj2",
                "plainobj3",
                "plainobj4",
                "str3",
                "str4",
                "bool3",
                "bool4",
                "int3",
                "int4",
                "float3",
                "float4",
                "obj3",
                "obj4",
            ]

            def validate(warnings: List[str]):
                for expected in expected_warnings:
                    found = False
                    for warning in warnings:
                        if expected in warning:
                            found = True
                            break
                    self.assertTrue(found, "expected warning not found")
                for unexpected in unexpected_warnings:
                    for warning in warnings:
                        self.assertFalse(
                            unexpected in warning,
                            f"Unexpected ${unexpected}' found in warning")

            # pulumi preview
            stack.preview(on_event=find_diagnostic_events)
            validate(events)

            # pulumi up
            events = []
            stack.up(on_event=find_diagnostic_events)
            validate(events)
        finally:
            stack.workspace.remove_stack(stack_name)