示例#1
0
def test_get_flow_image_raises_on_missing_info():
    flow_run = GraphQLResult(
        {
            "flow": GraphQLResult(
                {
                    "storage": Local().serialize(),
                    "environment": LocalEnvironment().serialize(),
                    "id": "id",
                }
            ),
            "id": "id",
        }
    )
    with pytest.raises(ValueError):
        image = get_flow_image(flow_run=flow_run)
示例#2
0
def test_local_agent_deploy_import_paths(monkeypatch, runner_token):
    popen = MagicMock()
    monkeypatch.setattr("prefect.agent.local.agent.Popen", popen)

    agent = LocalAgent(import_paths=["paths"])
    agent.deploy_flow(flow_run=GraphQLResult({
        "flow":
        GraphQLResult({"storage": Local(directory="test").serialize()}),
        "id":
        "id",
    }))

    assert popen.called
    assert len(agent.processes) == 1
    assert "paths" in popen.call_args[1]["env"]["PYTHONPATH"]
示例#3
0
def test_local_agent_deploy_processes_local_storage(monkeypatch, runner_token):

    popen = MagicMock()
    monkeypatch.setattr("prefect.agent.local.agent.Popen", popen)

    agent = LocalAgent()
    agent.deploy_flow(flow_run=GraphQLResult({
        "flow":
        GraphQLResult({"storage": Local(directory="test").serialize()}),
        "id":
        "id",
    }))

    assert popen.called
    assert len(agent.processes) == 1
示例#4
0
def test_add_flow_to_storage():
    with tempfile.TemporaryDirectory() as tmpdir:
        storage = Local(directory=tmpdir)
        f = Flow("test")
        assert f.name not in storage

        res = storage.add_flow(f)
        assert res.endswith("test.prefect")
        assert f.name in storage

        with open(os.path.join(tmpdir, "test.prefect"), "rb") as f:
            wat = f.read()

    assert isinstance(wat, bytes)
    assert cloudpickle.loads(wat).name == "test"
示例#5
0
def test_get_flow_image_run_config_default_value_from_core_version(version):
    flow_run = GraphQLResult({
        "flow":
        GraphQLResult({
            "core_version": version,
            "storage": Local().serialize(),
            "run_config": KubernetesRun().serialize(),
            "id": "id",
        }),
        "id":
        "id",
    })
    image = get_flow_image(flow_run)
    expected_version = version.split("+")[0] if version else "latest"
    assert image == f"prefecthq/prefect:all_extras-{expected_version}"
示例#6
0
 def get_run_task_kwargs(self, run_config, **kwargs):
     agent = ECSAgent(**kwargs)
     flow_run = GraphQLResult({
         "flow":
         GraphQLResult({
             "storage": Local().serialize(),
             "run_config": run_config.serialize(),
             "id": "flow-id",
             "version": 1,
             "name": "Test Flow",
             "core_version": "0.13.0",
         }),
         "id":
         "flow-run-id",
     })
     return agent.get_run_task_kwargs(flow_run, run_config)
示例#7
0
def test_get_flow_run_command(core_version, command):
    flow_run = GraphQLResult(
        {
            "flow": GraphQLResult(
                {
                    "storage": Local().serialize(),
                    "environment": LocalEnvironment().serialize(),
                    "id": "id",
                    "core_version": core_version,
                }
            ),
            "id": "id",
        }
    )

    assert get_flow_run_command(flow_run) == command
示例#8
0
def test_get_flow_run_command_works_if_core_version_not_on_response():
    legacy_command = "prefect execute cloud-flow"
    flow_run = GraphQLResult(
        {
            "flow": GraphQLResult(
                {
                    "storage": Local().serialize(),
                    "environment": LocalEnvironment().serialize(),
                    "id": "id",
                }
            ),
            "id": "id",
        }
    )

    assert get_flow_run_command(flow_run) == legacy_command
示例#9
0
def test_get_flow_image_run_config_image_on_RunConfig():
    flow_run = GraphQLResult({
        "flow":
        GraphQLResult({
            "storage":
            Local().serialize(),
            "run_config":
            KubernetesRun(image="myfancyimage").serialize(),
            "id":
            "id",
        }),
        "id":
        "id",
    })
    image = get_flow_image(flow_run)
    assert image == "myfancyimage"
示例#10
0
def test_k8s_agent_deploy_flow_uses_environment_metadata(monkeypatch, cloud_api):
    k8s_config = MagicMock()
    monkeypatch.setattr("kubernetes.config", k8s_config)

    batch_client = MagicMock()
    monkeypatch.setattr(
        "kubernetes.client.BatchV1Api", MagicMock(return_value=batch_client)
    )

    core_client = MagicMock()
    core_client.list_namespaced_pod.return_value = MagicMock(items=[])
    monkeypatch.setattr(
        "kubernetes.client.CoreV1Api", MagicMock(return_value=core_client)
    )

    get_jobs = MagicMock(return_value=[])
    monkeypatch.setattr(
        "prefect.agent.kubernetes.agent.KubernetesAgent.manage_jobs",
        get_jobs,
    )

    agent = KubernetesAgent()
    agent.deploy_flow(
        flow_run=GraphQLResult(
            {
                "flow": GraphQLResult(
                    {
                        "storage": Local().serialize(),
                        "environment": LocalEnvironment(
                            metadata={"image": "repo/name:tag"}
                        ).serialize(),
                        "id": "id",
                        "core_version": "0.13.0",
                    }
                ),
                "id": "id",
            }
        )
    )

    assert agent.batch_client.create_namespaced_job.called
    assert (
        agent.batch_client.create_namespaced_job.call_args[1]["body"]["spec"][
            "template"
        ]["spec"]["containers"][0]["image"]
        == "repo/name:tag"
    )
示例#11
0
def test_run_flow_calls_callbacks(monkeypatch):
    start_func = MagicMock()
    exit_func = MagicMock()

    environment = DaskKubernetesEnvironment(on_start=start_func, on_exit=exit_func)

    flow_runner = MagicMock()
    monkeypatch.setattr(
        "prefect.engine.get_default_flow_runner_class",
        MagicMock(return_value=flow_runner),
    )

    kube_cluster = MagicMock()
    monkeypatch.setattr("dask_kubernetes.KubeCluster", kube_cluster)

    with tempfile.TemporaryDirectory() as directory:
        d = Local(directory)
        d.add_flow(prefect.Flow("name"))

        gql_return = MagicMock(
            return_value=MagicMock(
                data=MagicMock(
                    flow_run=[
                        GraphQLResult(
                            {
                                "flow": GraphQLResult(
                                    {"name": "name", "storage": d.serialize(),}
                                )
                            }
                        )
                    ],
                )
            )
        )
        client = MagicMock()
        client.return_value.graphql = gql_return
        monkeypatch.setattr("prefect.environments.execution.dask.k8s.Client", client)

        with set_temporary_config({"cloud.auth_token": "test"}), prefect.context(
            {"flow_run_id": "id"}
        ):
            environment.run_flow()

        assert flow_runner.call_args[1]["flow"].name == "name"

    assert start_func.called
    assert exit_func.called
示例#12
0
def test_local_agent_deploy_flows_storage_continues(monkeypatch, runner_token):

    api = MagicMock()
    api.ping.return_value = True
    api.create_container.return_value = {"Id": "container_id"}
    monkeypatch.setattr("prefect.agent.local.agent.docker.APIClient",
                        MagicMock(return_value=api))

    agent = LocalAgent()
    agent.deploy_flows(flow_runs=[
        GraphQLResult({
            "flow": GraphQLResult({"storage": Local().serialize()}),
            "id": "id"
        })
    ])

    assert not api.pull.called
示例#13
0
def test_nomad_agent_deploy_flows_continues(monkeypatch, runner_token):
    requests = MagicMock()
    monkeypatch.setattr("prefect.agent.nomad.agent.requests", requests)

    agent = NomadAgent()
    agent.deploy_flows(flow_runs=[
        GraphQLResult(
            {
                "flow": GraphQLResult({
                    "storage": Local().serialize(),
                    "id": "id"
                }),
                "id": "id",
            })
    ])

    assert not requests.post.called
示例#14
0
def test_nomad_agent_deploy_flow_raises(monkeypatch, runner_token):
    requests = MagicMock()
    monkeypatch.setattr("prefect.agent.nomad.agent.requests", requests)

    agent = NomadAgent()

    with pytest.raises(ValueError):
        agent.deploy_flow(
            flow_run=GraphQLResult(
                {
                    "flow": GraphQLResult({"storage": Local().serialize(), "id": "id"}),
                    "id": "id",
                }
            )
        )

    assert not requests.post.called
示例#15
0
def test_get_flow_image_env_metadata():
    flow_run = GraphQLResult(
        {
            "flow": GraphQLResult(
                {
                    "storage": Local().serialize(),
                    "environment": LocalEnvironment(
                        metadata={"image": "repo/name:tag"}
                    ).serialize(),
                    "id": "id",
                }
            ),
            "id": "id",
        }
    )
    image = get_flow_image(flow_run=flow_run)
    assert image == "repo/name:tag"
示例#16
0
def test_multiple_flows_in_storage():
    with tempfile.TemporaryDirectory() as tmpdir:
        s = Local(directory=tmpdir)
        f = Flow("test")
        g = Flow("other")
        z = Flow("not")
        f_loc = s.add_flow(f)
        g_loc = s.add_flow(g)

        assert "test" in s
        assert "other" in s
        assert "not" not in s

        assert s.get_flow(f_loc) == f
        assert s.get_flow(g_loc) == g

        assert s.flows["test"] == f_loc
        assert s.flows["other"] == g_loc
示例#17
0
 def build_flow_run(self, config, storage=None):
     if storage is None:
         storage = Local()
     return GraphQLResult({
         "flow":
         GraphQLResult({
             "storage":
             storage.serialize(),
             "run_config":
             None if config is None else config.serialize(),
             "id":
             "new_id",
             "core_version":
             "0.13.0",
         }),
         "id":
         "id",
     })
示例#18
0
 def generate_task_definition(self, run_config, storage=None, **kwargs):
     if storage is None:
         storage = Local()
     agent = ECSAgent(**kwargs)
     flow_run = GraphQLResult({
         "flow":
         GraphQLResult({
             "storage": storage.serialize(),
             "run_config": run_config.serialize(),
             "id": "flow-id",
             "version": 1,
             "name": "Test Flow",
             "core_version": "0.13.0",
         }),
         "id":
         "flow-run-id",
     })
     return agent.generate_task_definition(flow_run, run_config)
def test_run_flow(monkeypatch):
    environment = FargateTaskEnvironment(executor_kwargs={"test": "here"})

    flow_runner = MagicMock()
    monkeypatch.setattr(
        "prefect.engine.get_default_flow_runner_class",
        MagicMock(return_value=flow_runner),
    )

    executor = MagicMock()
    monkeypatch.setattr(
        "prefect.engine.get_default_executor_class", MagicMock(return_value=executor),
    )

    with tempfile.TemporaryDirectory() as directory:
        d = Local(directory)
        d.add_flow(prefect.Flow("name"))

        gql_return = MagicMock(
            return_value=MagicMock(
                data=MagicMock(
                    flow_run=[
                        GraphQLResult(
                            {
                                "flow": GraphQLResult(
                                    {"name": "name", "storage": d.serialize(),}
                                )
                            }
                        )
                    ],
                )
            )
        )
        client = MagicMock()
        client.return_value.graphql = gql_return
        monkeypatch.setattr("prefect.environments.execution.base.Client", client)

        with set_temporary_config({"cloud.auth_token": "test"}), prefect.context(
            {"flow_run_id": "id"}
        ):
            environment.run_flow()

        assert flow_runner.call_args[1]["flow"].name == "name"
        assert executor.call_args[1] == {"test": "here"}
示例#20
0
def test_load_and_run_flow(monkeypatch, tmpdir):
    myflow = Flow("test-flow")

    # This is gross. Since the flow is pickled/unpickled, there's no easy way
    # to access the same object to set a flag. Resort to setting an environment
    # variable as a global flag that won't get copied eagerly through
    # cloudpickle.
    monkeypatch.setenv("TEST_RUN_CALLED", "FALSE")

    class MyEnvironment(Environment):
        def run(self, flow):
            assert flow is myflow
            os.environ["TEST_RUN_CALLED"] = "TRUE"

    myflow.environment = MyEnvironment()

    storage = Local(str(tmpdir))
    myflow.storage = storage
    storage.add_flow(myflow)

    gql_return = MagicMock(
        return_value=MagicMock(
            data=MagicMock(
                flow_run=[
                    GraphQLResult(
                        {
                            "flow": GraphQLResult(
                                {"name": myflow.name, "storage": storage.serialize()}
                            )
                        }
                    )
                ],
            )
        )
    )
    client = MagicMock()
    client.return_value.graphql = gql_return
    monkeypatch.setattr("prefect.environments.execution.base.Client", client)

    with set_temporary_config({"cloud.auth_token": "test"}), prefect.context(
        {"flow_run_id": "id"}
    ):
        load_and_run_flow()
    assert os.environ["TEST_RUN_CALLED"] == "TRUE"
示例#21
0
def test_nomad_agent_deploy_flow_raises(monkeypatch, runner_token):
    post = MagicMock()
    import requests  # this is imported within the agent's constructor

    monkeypatch.setattr(requests, "post", post)

    agent = NomadAgent()

    with pytest.raises(ValueError):
        agent.deploy_flow(
            flow_run=GraphQLResult(
                {
                    "flow": GraphQLResult({"storage": Local().serialize(), "id": "id"}),
                    "id": "id",
                }
            )
        )

    assert not post.called
示例#22
0
def test_docker_agent_deploy_flow_uses_environment_metadata(
        monkeypatch, cloud_api):
    api = MagicMock()
    api.ping.return_value = True
    api.create_container.return_value = {"Id": "container_id"}
    api.create_host_config.return_value = {"AutoRemove": True}
    monkeypatch.setattr(
        "prefect.agent.docker.agent.DockerAgent._get_docker_client",
        MagicMock(return_value=api),
    )

    agent = DockerAgent()
    agent.deploy_flow(flow_run=GraphQLResult({
        "flow":
        GraphQLResult({
            "id":
            "foo",
            "storage":
            Local().serialize(),
            "environment":
            LocalEnvironment(metadata={
                "image": "repo/name:tag"
            }).serialize(),
            "core_version":
            "0.13.0",
        }),
        "id":
        "id",
        "name":
        "name",
    }))

    assert api.pull.called
    assert api.create_container.called
    assert api.start.called

    assert api.create_host_config.call_args[1]["auto_remove"] is True
    assert api.create_container.call_args[1][
        "command"] == "prefect execute flow-run"
    assert api.create_container.call_args[1]["host_config"][
        "AutoRemove"] is True
    assert api.start.call_args[1]["container"] == "container_id"
示例#23
0
def test_local_agent_deploy_no_existing_python_path(monkeypatch, cloud_api):
    monkeypatch.delenv("PYTHONPATH", raising=False)

    popen = MagicMock()
    monkeypatch.setattr("prefect.agent.local.agent.Popen", popen)

    agent = LocalAgent(import_paths=["paths"])
    agent.deploy_flow(flow_run=GraphQLResult({
        "flow":
        GraphQLResult({
            "storage": Local(directory="test").serialize(),
            "id": "foo"
        }),
        "id":
        "id",
    }))

    assert popen.called
    assert len(agent.processes) == 1
    assert "paths" in popen.call_args[1]["env"]["PYTHONPATH"]
示例#24
0
def test_local_agent_deploy_null_or_univeral_run_config(
        monkeypatch, run_config):
    popen = MagicMock()
    monkeypatch.setattr("prefect.agent.local.agent.Popen", popen)

    agent = LocalAgent()

    agent.deploy_flow(flow_run=GraphQLResult(
        {
            "id": "id",
            "flow": {
                "storage": Local().serialize(),
                "run_config": run_config.serialize() if run_config else None,
                "id": "foo",
                "core_version": "0.13.0",
            },
        }, ))

    assert popen.called
    assert len(agent.processes) == 1
def test_run_flow_calls_callbacks(monkeypatch, tmpdir):
    start_func = MagicMock()
    exit_func = MagicMock()

    file_path = os.path.dirname(
        prefect.environments.execution.dask.k8s.__file__)
    environment = KubernetesJobEnvironment(os.path.join(file_path, "job.yaml"),
                                           on_start=start_func,
                                           on_exit=exit_func)

    flow_runner = MagicMock()
    monkeypatch.setattr(
        "prefect.engine.get_default_flow_runner_class",
        MagicMock(return_value=flow_runner),
    )

    d = Local(str(tmpdir))
    d.add_flow(prefect.Flow("name"))

    gql_return = MagicMock(return_value=MagicMock(data=MagicMock(flow_run=[
        GraphQLResult({
            "flow":
            GraphQLResult({
                "name": "name",
                "storage": d.serialize()
            })
        })
    ], )))
    client = MagicMock()
    client.return_value.graphql = gql_return
    monkeypatch.setattr("prefect.environments.execution.base.Client", client)

    with set_temporary_config({"cloud.auth_token":
                               "test"}), prefect.context({"flow_run_id":
                                                          "id"}):
        environment.run_flow()

    assert flow_runner.call_args[1]["flow"].name == "name"

    assert start_func.called
    assert exit_func.called
示例#26
0
def test_docker_agent_deploy_flow_storage_raises(monkeypatch, runner_token):

    monkeypatch.setattr("prefect.agent.agent.Client", MagicMock())
    api = MagicMock()
    api.ping.return_value = True
    api.create_container.return_value = {"Id": "container_id"}
    monkeypatch.setattr("prefect.agent.docker.agent.docker.APIClient",
                        MagicMock(return_value=api))

    agent = DockerAgent()

    with pytest.raises(ValueError):
        agent.deploy_flow(flow_run=GraphQLResult(
            {
                "flow": GraphQLResult({"storage": Local().serialize()}),
                "id": "id",
                "name": "name",
                "version": "version",
            }))

    assert not api.pull.called
示例#27
0
def test_local_agent_deploy_unsupported_run_config(monkeypatch):
    popen = MagicMock()
    monkeypatch.setattr("prefect.agent.local.agent.Popen", popen)

    agent = LocalAgent()

    with pytest.raises(TypeError,
                       match="Unsupported RunConfig type: Kubernetes"):
        agent.deploy_flow(flow_run=GraphQLResult(
            {
                "id": "id",
                "flow": {
                    "storage": Local().serialize(),
                    "run_config": KubernetesRun().serialize(),
                    "id": "foo",
                    "core_version": "0.13.0",
                },
            }, ))

    assert not popen.called
    assert len(agent.processes) == 0
示例#28
0
def test_k8s_agent_deploy_flow_raises(monkeypatch, runner_token):
    k8s_config = MagicMock()
    monkeypatch.setattr("kubernetes.config", k8s_config)

    batch_client = MagicMock()
    batch_client.create_namespaced_job.return_value = {}
    monkeypatch.setattr("kubernetes.client.BatchV1Api",
                        MagicMock(retrurn_value=batch_client))

    agent = KubernetesAgent()
    with pytest.raises(ValueError):
        agent.deploy_flow(flow_run=GraphQLResult(
            {
                "flow": GraphQLResult({
                    "storage": Local().serialize(),
                    "id": "id"
                }),
                "id": "id",
            }))

    assert not agent.batch_client.create_namespaced_job.called
示例#29
0
def test_k8s_agent_deploy_flow_raises(monkeypatch, cloud_api):
    k8s_config = MagicMock()
    monkeypatch.setattr("kubernetes.config", k8s_config)

    batch_client = MagicMock()
    monkeypatch.setattr(
        "kubernetes.client.BatchV1Api", MagicMock(return_value=batch_client)
    )

    core_client = MagicMock()
    core_client.list_namespaced_pod.return_value = MagicMock(items=[])
    monkeypatch.setattr(
        "kubernetes.client.CoreV1Api", MagicMock(return_value=core_client)
    )

    get_jobs = MagicMock(return_value=[])
    monkeypatch.setattr(
        "prefect.agent.kubernetes.agent.KubernetesAgent.manage_jobs",
        get_jobs,
    )

    agent = KubernetesAgent()
    with pytest.raises(ValueError):
        agent.deploy_flow(
            flow_run=GraphQLResult(
                {
                    "flow": GraphQLResult(
                        {
                            "storage": Local().serialize(),
                            "id": "id",
                            "environment": LocalEnvironment().serialize(),
                            "core_version": "0.13.0",
                        }
                    ),
                    "id": "id",
                }
            )
        )

    assert not agent.batch_client.create_namespaced_job.called
示例#30
0
def test_docker_agent_deploy_flow_unsupported_run_config(api):
    agent = DockerAgent()

    with pytest.raises(TypeError,
                       match="Unsupported RunConfig type: LocalRun"):
        agent.deploy_flow(flow_run=GraphQLResult({
            "flow":
            GraphQLResult({
                "storage": Local().serialize(),
                "run_config": LocalRun().serialize(),
                "id": "foo",
                "core_version": "0.13.0",
            }),
            "id":
            "id",
            "name":
            "name",
            "version":
            "version",
        }))

    assert not api.pull.called