diff --git a/lkr/embed/main.py b/lkr/embed/main.py new file mode 100644 index 0000000..bc69d05 --- /dev/null +++ b/lkr/embed/main.py @@ -0,0 +1,31 @@ +from typing import Annotated + +import typer + +from lkr.auth_service import get_auth +from lkr.embed.observability.embed_server import run_server + +__all__ = ["group"] + +group = typer.Typer(name="embed", help="Embed commands for LookML Repository") + + +@group.command() +def observability( + ctx: typer.Context, + port: Annotated[ + int, typer.Option("--port", help="Port to run the API on", envvar="PORT") + ] = 8080, + log_event_prefix: Annotated[ + str, typer.Option("--log-event-prefix", help="Prefix to use for the log events") + ] = "lkr:embed:observability", +): + """ + Spin up an API to do embed observability. **Important:** requires a user with the `admin` role. This will create + an endpoint where you can send embed user properties to it, it will create the sso embed url, then load it up into a selenium + browser. The browser will log the user in using the sso embed url, then it will navigate to the dashboard and start the observability tests. It will log structured payloads + with metadata in each step. You can then ingest these using tools your of choice + """ + sdk = get_auth(ctx).get_current_sdk() + + run_server(sdk=sdk, port=port, log_event_prefix=log_event_prefix) diff --git a/lkr/embed/observability/constants.py b/lkr/embed/observability/constants.py new file mode 100644 index 0000000..3e50dbc --- /dev/null +++ b/lkr/embed/observability/constants.py @@ -0,0 +1,8 @@ + +MAX_SESSION_LENGTH = 2592000 + +PERMISSIONS = [ + "access_data", + "see_user_dashboards", + "see_lookml_dashboards" +] diff --git a/lkr/embed/observability/create_sso_embed_url.py b/lkr/embed/observability/create_sso_embed_url.py new file mode 100644 index 0000000..b145f6b --- /dev/null +++ b/lkr/embed/observability/create_sso_embed_url.py @@ -0,0 +1,53 @@ +from typing import Any, Dict, List, Optional, TypedDict +from uuid import uuid4 + +from looker_sdk.sdk.api40.methods import Looker40SDK +from looker_sdk.sdk.api40.models import EmbedSsoParams +from pydantic import BaseModel, Field + +from lkr.embed.observability.constants import MAX_SESSION_LENGTH, PERMISSIONS + + +class CreateSSOEmbedUrlParams(BaseModel): + external_user_id: Optional[str] = Field(description="The external user id to create the sso embed url for", default_factory=lambda: f"embed-observability-{str(uuid4())}") + external_group_id: Optional[str] = None + models: Optional[List[str]] = Field(description="The models to create the sso embed url for") + permissions: Optional[List[str]] = Field(description="The permissions to create the sso embed url for") + dashboard: Optional[str] = Field(description="The dashboard to create the sso embed url for") + user_attribute: Optional[List[str]] = Field(description="The user attributes to create the sso embed url for") + user_timezone: Optional[str] = Field(description="The user timezone to create the sso embed url for") + group_ids: Optional[List[str]] = Field(description="The group ids to create the sso embed url for") + embed_domain: Optional[str] = Field(description="The embed domain to create the sso embed url for") + + def to_embed_sso_params(self) -> EmbedSsoParams: + all_permissions = list(set(PERMISSIONS + (self.permissions or []))) + return EmbedSsoParams( + external_user_id=self.external_user_id, + external_group_id=self.external_group_id, + models=self.models, + permissions=all_permissions, + target_url=f"/embed/dashboards/{self.dashboard}", + session_length=MAX_SESSION_LENGTH, + force_logout_login=True, + first_name=None, + last_name=None, + user_timezone=None, + group_ids=None, + user_attributes=None, + embed_domain=None, + + ) +class URLResponse(TypedDict): + url: str + external_user_id: str + +def create_sso_embed_url(sdk: Looker40SDK, *, data: Dict[str, Any]) -> URLResponse: + params = CreateSSOEmbedUrlParams( + external_user_id=data.get("external_user_id"), + external_group_id=data.get("external_group_id"), + models=data.get("models"), + permissions=data.get("permissions"), + dashboard=data.get("dashboard"), + ) + sso_url = sdk.create_sso_embed_url(body=params.to_embed_sso_params()) + return dict(url=sso_url.url, external_user_id=sso_url.external_user_id) \ No newline at end of file diff --git a/lkr/embed/observability/embed_container.html b/lkr/embed/observability/embed_container.html new file mode 100644 index 0000000..4678e7a --- /dev/null +++ b/lkr/embed/observability/embed_container.html @@ -0,0 +1,88 @@ + + +
+