Exemplo n.º 1
0
def login(token):
    """
    Login to Prefect Cloud with an api token to use for Cloud communication.

    \b
    Options:
        --token, -t         TEXT    A Prefect Cloud api token  [required]
    """

    client = Client()
    client.login(api_token=token)

    # Verify login obtained a valid api token
    try:
        client.graphql(query={"query": "hello"})
    except AuthorizationError:
        click.secho(
            "Error attempting to use Prefect API token {}".format(token),
            color="RED")
        return
    except ClientError:
        click.secho("Error attempting to communicate with Prefect Cloud",
                    color="RED")
        return

    click.echo("Login successful")
Exemplo n.º 2
0
def list_tokens():
    """
    DEPRECATED. Please use API keys instead.

    List your available Prefect Cloud API tokens.
    """
    click.secho(
        "WARNING: API tokens are deprecated. Please consider removing your remaining "
        "tokens and using API keys instead.",
        fg="yellow",
        err=True,  # Write to stderr in case the user is piping
    )

    client = Client()
    output = client.graphql(query={"query": {"api_token": {"id", "name"}}})

    if not output.get("data", None):
        click.secho("Unable to list API tokens", fg="red")
        return

    tokens = []
    for item in output.data.api_token:
        tokens.append([item.name, item.id])

    click.echo(
        tabulate(
            tokens,
            headers=["NAME", "ID"],
            tablefmt="plain",
            numalign="left",
            stralign="left",
        ))
Exemplo n.º 3
0
def revoke_token(id):
    """
    DEPRECATED. Please use API keys instead.

    Revote a Prefect Cloud API token

    \b
    Options:
        --id, -i    TEXT    The id of a token to revoke
    """
    check_override_auth_token()

    client = Client()

    output = client.graphql(
        query={
            "mutation($input: delete_api_token_input!)": {
                "delete_api_token(input: $input)": {"success"}
            }
        },
        variables=dict(input=dict(token_id=id)),
    )

    if not output.get("data",
                      None) or not output.data.delete_api_token.success:
        click.secho("Unable to revoke token with ID {}".format(id), fg="red")
        return

    click.secho("Token successfully revoked", fg="green")
Exemplo n.º 4
0
def add(token, config_path):
    """
    Add a new Prefect Cloud auth token to use for Cloud communication.

    \b
    Options:
        --token, -t         TEXT    A Prefect Cloud auth token                                          [required]
        --config-path, -c   TEXT    Path to a Prefect config.toml, defaults to `~/.prefect/config.toml`
    """
    abs_directory = os.path.abspath(os.path.expanduser(config_path))
    if not os.path.exists(abs_directory):
        click.secho("{} does not exist".format(config_path), fg="red")
        return

    config = toml.load(abs_directory)
    if not config.get("cloud"):
        config["cloud"] = {}
    config["cloud"]["auth_token"] = token

    with open(abs_directory, "w") as file:
        toml.dump(config, file)
        click.echo("Auth token added to Prefect config")

        client = Client()
        client.token = token
        result = client.graphql(query={"query": "hello"})
        if not result.data.hello:
            click.secho(
                "Error attempting to use Prefect auth token {}".format(result))
Exemplo n.º 5
0
def list_keys():
    """
    List available Prefect Cloud API keys.
    """
    client = Client()

    response = client.graphql(
        query={
            "query": {
                "auth_api_key": {
                    "id": True,
                    "name": True,
                    "expires_at": True,
                }
            }
        })
    keys = response.get("data", {}).get("auth_api_key")
    if keys is None:
        raise TerminalError(
            f"Unexpected response from Prefect Cloud: {response}")

    if not keys:
        click.secho("You have not created any API keys", fg="yellow")

    else:
        click.echo(
            tabulate(
                [(key.name, key.id, key.expires_at or "NEVER")
                 for key in keys],
                headers=["NAME", "ID", "EXPIRES AT"],
                tablefmt="plain",
                numalign="left",
                stralign="left",
            ))
Exemplo n.º 6
0
def list_tokens():
    """
    List your available Prefect Cloud API tokens.
    """
    check_override_auth_token()

    client = Client()

    output = client.graphql(query={"query": {"api_token": {"id", "name"}}})

    if not output.get("data", None):
        click.secho("Unable to list API tokens", fg="red")
        return

    tokens = []
    for item in output.data.api_token:
        tokens.append([item.name, item.id])

    click.echo(
        tabulate(
            tokens,
            headers=["NAME", "ID"],
            tablefmt="plain",
            numalign="left",
            stralign="left",
        )
    )
Exemplo n.º 7
0
def create_token(name, scope):
    """
    Create a Prefect Cloud API token.

    For more info on API tokens visit https://docs.prefect.io/orchestration/concepts/api.html

    \b
    Options:
        --name, -n      TEXT    A name to give the generated token
        --scope, -s     TEXT    A scope for the token
    """
    check_override_auth_token()

    client = Client()

    output = client.graphql(
        query={
            "mutation($input: create_api_token_input!)": {
                "create_api_token(input: $input)": {"token"}
            }
        },
        variables=dict(input=dict(name=name, scope=scope)),
    )

    if not output.get("data", None):
        click.secho("Issue creating API token", fg="red")
        return

    click.echo(output.data.create_api_token.token)
Exemplo n.º 8
0
    def execute(  # type: ignore
            self,
            storage: "Storage",
            flow_location: str,
            **kwargs: Any  # type: ignore
    ) -> None:
        flow_run_info = None
        flow_run_id = prefect.context.get("flow_run_id")
        if self._on_execute:
            # If an on_execute Callable has been provided, retrieve the flow run parameters
            # and then allow the Callable a chance to update _provider_kwargs. This allows
            # better sizing of the cluster resources based on parameters for this Flow run.
            try:
                client = Client()
                flow_run_info = client.get_flow_run_info(flow_run_id)
                parameters = flow_run_info.parameters or {}  # type: ignore
                self._on_execute(parameters, self._provider_kwargs)
            except Exception as exc:
                self.logger.info(
                    "Failed to retrieve flow run info with error: {}".format(
                        repr(exc)))
        if "image" not in self._provider_kwargs or not self._provider_kwargs.get(
                "image"):
            # If image is not specified, use the Flow's image so that dependencies are
            # identical on all containers: Flow runner, Dask scheduler, and Dask workers
            flow_id = prefect.context.get("flow_id")
            try:
                client = Client()
                if not flow_id:  # We've observed cases where flow_id is None
                    if not flow_run_info:
                        flow_run_info = client.get_flow_run_info(flow_run_id)
                    flow_id = flow_run_info.flow_id
                flow_info = client.graphql("""query {
                  flow(where: {id: {_eq: "%s"}}) {
                    storage
                  }
                }""" % flow_id)
                storage_info = flow_info["data"]["flow"][0]["storage"]
                image = "{}/{}:{}".format(
                    storage_info["registry_url"],
                    storage_info["image_name"],
                    storage_info["image_tag"],
                )
                self.logger.info(
                    "Using Flow's Docker image for Dask scheduler & workers: {}"
                    .format(image))
                self._provider_kwargs["image"] = image
            except Exception as exc:
                self.logger.info(
                    "Failed to retrieve flow info with error: {}".format(
                        repr(exc)))

        self._create_dask_cluster()

        self.logger.info(
            "Executing on dynamically created Dask Cluster with scheduler address: {}"
            .format(self.executor_kwargs["address"]))
        super().execute(storage, flow_location, **kwargs)
Exemplo n.º 9
0
    def _query_for_task_runs(
        where: dict,
        order_by: dict = None,
        error_on_empty: bool = True,
    ) -> List[dict]:
        """
        Query for task run data necessary to initialize `TaskRunView` instances
        with `TaskRunView.from_task_run_data`.

        Args:
            - where (required): The Hasura `where` clause to filter by
            - order_by (optional): An optional Hasura `order_by` clause to order results
                by.
            - error_on_empty (optional): If `True` and no tasks are found, a `ValueError`
                will be raised.

        Returns:
           A list of dicts containing task run data
        """
        client = Client()

        query_args = {"where": where}
        if order_by is not None:
            query_args["order_by"] = order_by

        query = {
            "query": {
                with_args("task_run", query_args): {
                    "id": True,
                    "name": True,
                    "task": {
                        "id": True,
                        "slug": True
                    },
                    "map_index": True,
                    "serialized_state": True,
                    "flow_run_id": True,
                }
            }
        }

        result = client.graphql(query)
        task_runs = result.get("data", {}).get("task_run", None)

        if task_runs is None:
            raise ValueError(
                f"Received bad result while querying for task runs where {where}: "
                f"{result}")

        if not task_runs and error_on_empty:
            raise ValueError(
                f"No task runs found while querying for task runs where {where}"
            )

        return task_runs
Exemplo n.º 10
0
    def _query_for_tenants(
        where: dict,
        order_by: dict = None,
        error_on_empty: bool = True,
    ) -> List[dict]:
        """
        Query for tenant data necessary to initialize `TenantView` instances with
        `TenantView._from_tenant_data`.

        Args:
            - where (required): The Hasura `where` clause to filter by
            - order_by (optional): An optional Hasura `order_by` clause to order
                 results by
            - error_on_empty (optional): If `True` and no tenants are found, a
                `ValueError` will be raised

        Returns:
            A list of dicts of tenant information
        """
        client = Client()

        query_args = {"where": where}
        if order_by is not None:
            query_args["order_by"] = order_by

        tenant_query = {
            "query": {
                with_args("tenant", query_args): {
                    "id",
                    "slug",
                    "name",
                }
            }
        }

        result = client.graphql(tenant_query)
        tenants = result.get("data", {}).get("tenant", None)

        if tenants is None:
            raise ValueError(
                f"Received bad result while querying for tenants where {where}: "
                f"{result}")

        if not tenants:  # Empty list
            if error_on_empty:
                raise ValueError(
                    f"No results found while querying for tenants where {where!r}"
                )
            return []

        # Return a list
        return tenants
Exemplo n.º 11
0
def login(token):
    """
    Log in to Prefect Cloud with an api token to use for Cloud communication.

    \b
    Options:
        --token, -t         TEXT    A Prefect Cloud api token  [required]
    """
    check_override_auth_token()

    client = Client(api_token=token)

    # Verify login obtained a valid api token
    try:
        output = client.graphql(
            query={"query": {
                "user": {
                    "default_membership": "tenant_id"
                }
            }})

        # Log into default membership
        success_login = client.login_to_tenant(
            tenant_id=output.data.user[0].default_membership.tenant_id)

        if not success_login:
            raise AuthorizationError

    except AuthorizationError:
        click.secho(
            f"Error attempting to use Prefect API token {token}. "
            "Please check that you are providing a USER scoped Personal Access Token.\n"
            "For more information visit the documentation for USER tokens at "
            "https://docs.prefect.io/orchestration/concepts/tokens.html#user",
            fg="red",
        )
        return
    except ClientError:
        click.secho(
            "Error attempting to communicate with Prefect Cloud. "
            "Please check that you are providing a USER scoped Personal Access Token.\n"
            "For more information visit the documentation for USER tokens at "
            "https://docs.prefect.io/orchestration/concepts/tokens.html#user",
            fg="red",
        )
        return

    # save token
    client.save_api_token()

    click.secho("Login successful!", fg="green")
Exemplo n.º 12
0
def is_agent_up_prefect_cloud(pytestconfig):
    """
    Check if the agent is up on Prefect Cloud
    """

    # get prefect agent API token
    prefect_agent_token = pytestconfig.getoption("prefect_agent_token")

    # Instantiate the prefect client
    prefect_client = Client(api_token=prefect_agent_token)

    # query prefect cloud agents
    query = """
        query RunningFlows {
        agent {
                labels,
                last_queried
            }
        }
    """

    agents = prefect_client.graphql(query=query)["data"]["agent"]
    environment_agent_info = [
        item for item in agents
        if f"{ENV}_dataflow_automation" in item["labels"]
    ]
    if len(environment_agent_info) == 0:
        # agent doesn't even appear on prefect cloud yet
        return ResourceCheckStatus.RETRY
    else:
        last_queried_time = environment_agent_info[0]["last_queried"]

        # date
        last_queried_time = datetime.strptime(last_queried_time,
                                              "%Y-%m-%dT%H:%M:%S.%f%z")

        difference = datetime.utcnow().replace(
            tzinfo=None) - last_queried_time.replace(tzinfo=None)

        # If the agent has been queried recently (meaning it is up)
        if int(difference.total_seconds()) < 15:
            return ResourceCheckStatus.FINISHED
        else:
            # agent appears on prefect cloud but doesn't seem to be up
            return ResourceCheckStatus.RETRY
Exemplo n.º 13
0
def revoke_key(id):
    """
    Revoke a Prefect Cloud API key.
    """
    client = Client()

    output = client.graphql(
        query={
            "mutation($input: delete_api_key_input!)": {
                "delete_api_key(input: $input)": {"success"}
            }
        },
        variables=dict(input=dict(key_id=id)),
    )

    if not output.get("data", None) or not output.data.delete_api_key.success:
        raise TerminalError(f"Unable to revoke key {id!r}")

    click.secho("Key successfully revoked!", fg="green")
Exemplo n.º 14
0
def login(token):
    """
    Log in to Prefect Cloud with an api token to use for Cloud communication.

    \b
    Options:
        --token, -t         TEXT    A Prefect Cloud api token  [required]
    """
    check_override_auth_token()

    client = Client(api_token=token)

    # Verify login obtained a valid api token
    try:
        output = client.graphql(
            query={"query": {
                "user": {
                    "default_membership": "tenant_id"
                }
            }})

        # Log into default membership
        success_login = client.login_to_tenant(
            tenant_id=output.data.user[0].default_membership.tenant_id)

        if not success_login:
            raise AuthorizationError

    except AuthorizationError:
        click.secho(
            "Error attempting to use Prefect API token {}".format(token),
            fg="red")
        return
    except ClientError:
        click.secho("Error attempting to communicate with Prefect Cloud",
                    fg="red")
        return

    # save token
    client.save_api_token()

    click.secho("Login successful!", fg="green")
Exemplo n.º 15
0
def create_project_if_not_exists(client: prefect.Client,
                                 project_name: str) -> None:
    """Checks whether a project named "Monitorfish" already exists in Prefect Server.
    If not, the project is created.

    Args:
        client (prefect.Client): Prefect client instance

    Raises:
        ValueError: if more than 1 project with the name "Monitorfish" are found.
    """
    r = client.graphql(
        'query{project(where: {name: {_eq : "Monitorfish"}}){name}}')
    projects = r["data"]["project"]
    if len(projects) == 0:
        print("Monitorfish project does not exists, it will be created.")
        client.create_project(project_name)
    elif len(projects) == 1:
        print("Monitorfish project already exists. Skipping project creation.")
    else:
        raise ValueError(
            "Several projects with the name 'Monitorfish' were found.")
Exemplo n.º 16
0
def create_token(name, scope):
    """
    DEPRECATED. Please use API keys instead.

    Create a Prefect Cloud API token.

    For more info on API tokens visit https://docs.prefect.io/orchestration/concepts/api.html

    \b
    Options:
        --name, -n      TEXT    A name to give the generated token
        --scope, -s     TEXT    A scope for the token
    """
    click.secho(
        "WARNING: API tokens are deprecated. Please use `prefect auth create-key` to "
        "create an API key instead.",
        fg="yellow",
        err=True,  # Write to stderr in case the user is piping
    )

    client = Client()

    output = client.graphql(
        query={
            "mutation($input: create_api_token_input!)": {
                "create_api_token(input: $input)": {"token"}
            }
        },
        variables=dict(input=dict(name=name, scope=scope)),
    )

    if not output.get("data", None):
        click.secho("Issue creating API token", fg="red")
        return

    click.echo(output.data.create_api_token.token)
Exemplo n.º 17
0
def login(key, token):
    """
    Login to Prefect Cloud

    Create an API key in the UI then login with it here:

        $ prefect auth login -k YOUR-KEY

    You will be switched to the default tenant associated with the key. After login,
    your available tenants can be seen with `prefect auth list-tenants` and you can
    change the default tenant on this machine using `prefect auth switch-tenants`.

    The given key will be stored on disk for later access. Prefect will default to using
    this key for all interaction with the API but frequently overrides can be passed to
    individual commands or functions. To remove your key from disk, see
    `prefect auth logout`.

    This command has backwards compatibility support for API tokens, which are a
    deprecated form of authentication with Prefect Cloud
    """
    if not key and not token:
        raise TerminalError("You must supply an API key or token!")

    if key and token:
        raise TerminalError("You cannot supply both an API key and token")

    abort_on_config_api_key(
        "To log in with the CLI, remove the config key `prefect.cloud.api_key`"
    )

    # Attempt to treat the input like an API key even if it is passed as a token
    client = Client(api_key=key or token)

    try:
        default_tenant = client.get_default_tenant()
    except AuthorizationError:
        if key:  # We'll catch an error again later if using a token
            raise TerminalError("Unauthorized. Invalid Prefect Cloud API key.")
    except ClientError:
        raise TerminalError(
            "Error attempting to communicate with Prefect Cloud.")
    else:
        if not default_tenant and key:
            raise TerminalError(
                "Failed to find a tenant associated with the given API key!")

        elif default_tenant:  # Successful login
            if token:
                click.secho(
                    "WARNING: You logged in with an API key using the `--token` flag "
                    "which is deprecated. Please use `--key` instead.",
                    fg="yellow",
                )
            client.save_auth_to_disk()
            click.secho("Login successful!", fg="green")
            return

        # If there's not a tenant id, we've been given an actual token, fallthrough to
        # the backwards compatibility token auth

    # Backwards compatibility for tokens
    if token:
        check_override_auth_token()
        client = Client(api_token=token)

        # Verify they're not also using an API key
        if client.api_key:
            raise TerminalError(
                "You have already logged in with an API key and cannot use a token."
            )

        click.secho(
            "WARNING: API tokens are deprecated. Please create an API key and use "
            "`prefect auth login --key <KEY>` to login instead.",
            fg="yellow",
        )

        # Verify login obtained a valid api token
        try:
            output = client.graphql(
                query={"query": {
                    "user": {
                        "default_membership": "tenant_id"
                    }
                }})

            # Log into default membership
            success_login = client.login_to_tenant(
                tenant_id=output.data.user[0].default_membership.tenant_id)

            if not success_login:
                raise AuthorizationError

        except AuthorizationError:
            click.secho(
                "Error attempting to use the given API token. "
                "Please check that you are providing a USER scoped Personal Access Token.\n"
                "For more information visit the documentation for USER tokens at "
                "https://docs.prefect.io/orchestration/concepts/tokens.html#user",
                fg="red",
            )
            return
        except ClientError:
            click.secho(
                "Error attempting to communicate with Prefect Cloud. "
                "Please check that you are providing a USER scoped Personal Access Token.\n"
                "For more information visit the documentation for USER tokens at "
                "https://docs.prefect.io/orchestration/concepts/tokens.html#user",
                fg="red",
            )
            return

        # save token
        client.save_api_token()

        click.secho("Login successful!", fg="green")
Exemplo n.º 18
0
from os import walk, path
from prefect import Client
from importlib import import_module
from itertools import groupby

client = Client()
flows = client.graphql('''query {
    flow { project { name } archived name id }
}''').to_dict()['data']['flow']

flows_by_project = {
    project: {
        flow['id']: flow['name']
        for flow in filter(lambda flow: not flow['archived'], project_flows)
    }
    for project, project_flows in groupby(flows,
                                          lambda flow: flow['project']['name'])
}

(root, projects, _) = next(walk(path.dirname(__file__)))

for project_name in projects:
    if project_name in flows_by_project:
        for old_flow in flows_by_project[project_name].keys():
            error = client.graphql(f'''mutation {{
                archive_flow(input: {{ flow_id: "{old_flow}" }}) {{ error }}
            }}''').to_dict()['data']['archive_flow']['error']

            print('Archiving existing flow %s.. %s' %
                  (old_flow, error or 'OK'))
Exemplo n.º 19
0
def create_key(name, expire, quiet):
    """
    Create a Prefect Cloud API key for authentication with your current user
    """
    # TODO: Add service account associated key creation eventually

    # Parse the input expiration
    if expire is not None:
        try:
            expires_at = pendulum.parse(expire, strict=False)
        except pendulum.parsing.exceptions.ParserError as exc:
            raise TerminalError(
                f"Failed to parse expiration time. {exc}\n"
                "Please pass a date in a dateutil parsable format.")

        if expires_at.diff(abs=False).in_seconds() > 0:
            raise TerminalError(
                f"Given expiration time {expire!r} is a time in the past: {expires_at}"
            )
        expire_msg = f" that will expire {expires_at.diff_for_humans()}"
    else:
        expires_at = None
        expire_msg = ""

    client = Client()

    # We must retrieve our own user id first since you could be creating a key for a SA
    if not quiet:
        click.echo("Retrieving user information...")

    response = client.graphql({"query": {"auth_info": {"user_id"}}})
    user_id = response.get("data", {}).get("auth_info", {}).get("user_id")
    if not user_id:
        raise TerminalError(
            "Failed to retrieve the current user id from Prefect Cloud")

    # Actually create the key
    if not quiet:
        click.echo(f"Creating key{expire_msg}...")
    response = client.graphql(
        query={
            "mutation($input: create_api_key_input!)": {
                "create_api_key(input: $input)": {"key"}
            }
        },
        variables=dict(input=dict(
            name=name,
            user_id=user_id,
            expires_at=expires_at.in_tz("utc").isoformat(
            ) if expires_at else None,
        )),
    )

    key = response.get("data", {}).get("create_api_key", {}).get("key")
    if key is None:
        raise TerminalError(
            f"Unexpected response from Prefect Cloud: {response}")

    if quiet:
        click.echo(key)
    else:
        click.echo(
            "This is the only time this key will be displayed! Store it somewhere safe."
        )
        click.secho(f"Successfully created key: {key}", fg="green")
Exemplo n.º 20
0
    def run(
        self,
        flow_name: str = None,
        project_name: str = None,
        parameters: dict = None,
        run_config: RunConfig = None,
        new_flow_context: dict = None,
        run_name: str = None,
        idempotency_key: str = None,
        scheduled_start_time: datetime.datetime = None,
    ) -> str:
        """
        Run method for the task; responsible for scheduling the specified flow run.

        Args:
            - flow_name (str, optional): the name of the flow to schedule; if not provided,
                this method will use the flow name provided at initialization
            - project_name (str, optional): the Cloud project in which the flow is located; if
                not provided, this method will use the project provided at initialization. If
                running with Prefect Core's server as the backend, this should not be provided.
            - parameters (dict, optional): the parameters to pass to the flow run being
                scheduled; if not provided, this method will use the parameters provided at
                initialization
            - run_config (RunConfig, optional): a run-config to use for this flow
                run, overriding any existing flow settings.
            - new_flow_context (dict, optional): the optional run context for the new flow run
            - run_name (str, optional): name to be set for the flow run
            - idempotency_key (str, optional): a unique idempotency key for scheduling the
                flow run. Duplicate flow runs with the same idempotency key will only create
                a single flow run. This is useful for ensuring that only one run is created
                if this task is retried. If not provided, defaults to the active `task_run_id`.
            - scheduled_start_time (datetime, optional): the time to schedule the execution
                for; if not provided, defaults to now

        Returns:
            - str: the ID of the newly-scheduled flow run

        Raises:
            - ValueError: if flow was not provided, cannot be found, or if a project name was
                not provided while using Cloud as a backend

        Example:
            ```python
            from prefect.tasks.prefect.flow_run import StartFlowRun

            kickoff_task = StartFlowRun(project_name="Hello, World!", flow_name="My Cloud Flow")
            ```

        """

        # verify that flow and project names were passed where necessary
        if flow_name is None:
            raise ValueError("Must provide a flow name.")
        if project_name is None:
            raise ValueError("Must provide a project name.")

        where_clause = {
            "name": {
                "_eq": flow_name
            },
            "archived": {
                "_eq": False
            },
            "project": {
                "name": {
                    "_eq": project_name
                }
            },
        }

        # find the flow ID to schedule
        query = {
            "query": {
                with_args(
                    "flow",
                    {
                        "where": where_clause,
                        "order_by": {
                            "version": EnumValue("desc")
                        },
                        "limit": 1,
                    },
                ): {"id"}
            }
        }

        client = Client()
        flow = client.graphql(query).data.flow

        # verify that a flow has been returned
        if not flow:
            raise ValueError("Flow '{}' not found.".format(flow_name))

        # grab the ID for the most recent version
        flow_id = flow[0].id

        if idempotency_key is None:
            idempotency_key = prefect.context.get("task_run_id", None)

        # providing an idempotency key ensures that retries for this task
        # will not create additional flow runs
        flow_run_id = client.create_flow_run(
            flow_id=flow_id,
            parameters=parameters,
            run_config=run_config,
            idempotency_key=idempotency_key,
            context=new_flow_context,
            run_name=run_name,
            scheduled_start_time=scheduled_start_time,
        )

        self.logger.debug(f"Flow Run {flow_run_id} created.")

        self.logger.debug(
            f"Creating link artifact for Flow Run {flow_run_id}.")
        run_link = client.get_cloud_url("flow-run", flow_run_id, as_user=False)
        create_link(urlparse(run_link).path)
        self.logger.info(f"Flow Run: {run_link}")

        if not self.wait:
            return flow_run_id

        while True:
            time.sleep(self.poll_interval.total_seconds())
            flow_run_state = client.get_flow_run_info(flow_run_id).state
            if flow_run_state.is_finished():
                exc = signal_from_state(flow_run_state)(
                    f"{flow_run_id} finished in state {flow_run_state}")
                raise exc
Exemplo n.º 21
0
    def execute(  # type: ignore
        self, flow: "Flow", **kwargs: Any  # type: ignore
    ) -> None:
        """
        Execute a flow run on a dask-cloudprovider cluster.

        Args:
            - flow (Flow): the Flow object
            - **kwargs (Any): Unused
        """
        flow_run_info = None
        flow_run_id = prefect.context.get("flow_run_id")
        if self._on_execute:
            # If an on_execute Callable has been provided, retrieve the flow run parameters
            # and then allow the Callable a chance to update _provider_kwargs. This allows
            # better sizing of the cluster resources based on parameters for this Flow run.
            try:
                client = Client()
                flow_run_info = client.get_flow_run_info(flow_run_id)
                parameters = flow_run_info.parameters or {}  # type: ignore
                self._on_execute(parameters, self._provider_kwargs)
            except Exception as exc:
                self.logger.info(
                    "Failed to retrieve flow run info with error: {}".format(repr(exc))
                )
        if "image" not in self._provider_kwargs or not self._provider_kwargs.get(
            "image"
        ):
            # If image is not specified, use the Flow's image so that dependencies are
            # identical on all containers: Flow runner, Dask scheduler, and Dask workers
            flow_id = prefect.context.get("flow_id")
            try:
                client = Client()
                if not flow_id:  # We've observed cases where flow_id is None
                    if not flow_run_info:
                        flow_run_info = client.get_flow_run_info(flow_run_id)
                    flow_id = flow_run_info.flow_id
                flow_info = client.graphql(
                    """query {
                  flow(where: {id: {_eq: "%s"}}) {
                    storage
                  }
                }"""
                    % flow_id
                )
                storage_info = flow_info["data"]["flow"][0]["storage"]
                image = "{}/{}:{}".format(
                    storage_info["registry_url"],
                    storage_info["image_name"],
                    storage_info["image_tag"],
                )
                self.logger.info(
                    "Using Flow's Docker image for Dask scheduler & workers: {}".format(
                        image
                    )
                )
                self._provider_kwargs["image"] = image
            except Exception as exc:
                self.logger.info(
                    "Failed to retrieve flow info with error: {}".format(repr(exc))
                )

        self._create_dask_cluster()

        self.logger.info(
            "Executing on dynamically created Dask Cluster with scheduler address: {}".format(
                self.executor_kwargs["address"]
            )
        )
        if self.on_start:
            self.on_start()

        try:
            from prefect.engine import get_default_flow_runner_class
            from prefect.executors import DaskExecutor

            runner_cls = get_default_flow_runner_class()
            runner_cls(flow=flow).run(executor=DaskExecutor(**self.executor_kwargs))
        except Exception as exc:
            self.logger.exception(
                "Unexpected error raised during flow run: {}".format(exc)
            )
            raise
        finally:
            if self.on_exit:
                self.on_exit()
def change_prev_flow_state(number, secret):
    logger = prefect.context.get("logger")
    prev_random_number = prefect.context.get("prev_random_number")
    prev_flow_run_id = prefect.context.get("prev_flow_run_id")

    logger.info(f"The number retrieved from Context was: {prev_random_number}")
    logger.info(f"The number submitted to this Task was: {number}")

    client = Client(api_token=secret)
    client.login_to_tenant(tenant_slug="kmw-cloud")

    if number is None:
        logger.info("Outcome: Your number was None")
        pass
    elif number < 50:
        logger.info(f"Outcome: Your number was {number}, which is < 50")
        pass
    elif number < 70:
        set_flow_run_state = client.graphql(query="""
                mutation SetFlowRunStates($flowRunId: UUID!, $state: JSON!) {
                    set_flow_run_states(
                        input: {
                        states: [{ flow_run_id: $flowRunId, state: $state }]
                        }
                    ) {
                        states {
                        id
                        status
                        message
                        }
                    }
                }
            """,
                                            variables={
                                                "flowRunId": prev_flow_run_id,
                                                "state": {
                                                    "type": "Cancelled"
                                                }
                                            })
    elif number < 90:
        set_flow_run_state = client.graphql(query="""
                mutation SetFlowRunStates($flowRunId: UUID!, $state: JSON!) {
                    set_flow_run_states(
                        input: {
                        states: [{ flow_run_id: $flowRunId, state: $state }]
                        }
                    ) {
                        states {
                        id
                        status
                        message
                        }
                    }
                }
            """,
                                            variables={
                                                "flowRunId": prev_flow_run_id,
                                                "state": {
                                                    "type": "Finished"
                                                }
                                            })
    else:
        set_flow_run_state = client.graphql(query="""
                mutation SetFlowRunStates($flowRunId: UUID!, $state: JSON!) {
                    set_flow_run_states(
                        input: {
                        states: [{ flow_run_id: $flowRunId, state: $state }]
                        }
                    ) {
                        states {
                        id
                        status
                        message
                        }
                    }
                }
            """,
                                            variables={
                                                "flowRunId": prev_flow_run_id,
                                                "state": {
                                                    "type": "Skipped"
                                                }
                                            })
Exemplo n.º 23
0
from prefect import Client
from prefect.utilities.graphql import with_args

c = Client()

name = "my_flow"
c.graphql({"query": {with_args("flow", {"where": {"name": {"_eq": name}}}): "id"}})

# c.graphql({"query": "'query' {'flow'('where': { 'name': { '_eq': 'ltest' } }) {'id'}}"})