Accede a los datos de Workday con Spark

Managed Service para Apache Spark te permite consultar y analizar datos empresariales externos directamente desde tus cargas de trabajo de Spark. Puedes usar el controlador JDBC de Workday Live Data Query para conectarte a tu usuario de Workday, cargar conjuntos de datos de Workday en tiempo real en Spark DataFrames y, luego, integrar esos datos en tu canalización de estadísticas en Google Cloud.

En esta guía, configurarás Workday Live Data Query, almacenarás tu clave privada de forma segura en Secret Manager y usarás la extensión de Google Cloud Data Agent Kit para ejecutar un notebook de PySpark en Visual Studio Code o el editor de Cloud Shell en Managed Service para Apache Spark.

Costos

La extensión Data Agent Kit está disponible sin costo adicional. Sin embargo, en esta guía se usan los siguientes componentes facturables de Google Cloud:

Para generar una estimación de costos en función del uso previsto, usa la calculadora de precios.

Antes de comenzar

  1. Accede a tu cuenta de Google Cloud . Si eres nuevo en Google Cloud, crea una cuenta para evaluar el rendimiento de nuestros productos en situaciones reales. Los clientes nuevos también obtienen $300 en créditos gratuitos para ejecutar, probar y, además, implementar cargas de trabajo.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that you have the permissions required to complete this guide.

  4. Verify that billing is enabled for your Google Cloud project.

  5. Enable the Dataproc, Dataplex, Cloud Storage, and Secret Manager APIs, if any are not already enabled.

    Roles required to enable APIs

    To enable APIs, you need the serviceusage.services.enable permission. If you created the project, then you likely already have this permission through the Owner role (roles/owner). Otherwise, you can get this permission through the Service Usage Admin role (roles/serviceusage.serviceUsageAdmin). Learn how to grant roles.

    Enable the APIs

  6. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  7. Verify that you have the permissions required to complete this guide.

  8. Verify that billing is enabled for your Google Cloud project.

  9. Enable the Dataproc, Dataplex, Cloud Storage, and Secret Manager APIs, if any are not already enabled.

    Roles required to enable APIs

    To enable APIs, you need the serviceusage.services.enable permission. If you created the project, then you likely already have this permission through the Owner role (roles/owner). Otherwise, you can get this permission through the Service Usage Admin role (roles/serviceusage.serviceUsageAdmin). Learn how to grant roles.

    Enable the APIs

Roles de Identity and Access Management (IAM) necesarios

Se requieren ciertos roles de IAM para ejecutar los ejemplos de esta página. Según las políticas de la organización, es posible que ya se hayan otorgado estos roles. Para verificar las asignaciones de roles, consulta ¿Necesitas otorgar roles?. Para obtener más información para otorgar roles, consulta Administra el acceso a proyectos, carpetas y organizaciones.

Los roles que necesitas dependen de cómo se ejecuta tu carga de trabajo. Los entornos de ejecución sin servidores 2.3 y anteriores de Managed Service para Apache Spark ejecutan cargas de trabajo como una cuenta de servicio. Los entornos de ejecución sin servidores 3.0 y posteriores de Managed Service para Apache Spark ejecutan cargas de trabajo de forma predeterminada con tus credenciales de usuario final (EUC), por lo que otorgas roles de acceso a los datos a tu cuenta de usuario en lugar de a una cuenta de servicio. Si especificas una cuenta de servicio personalizada para un entorno de ejecución 3.0 o posterior, la carga de trabajo se ejecuta con las credenciales de la cuenta de servicio. Para obtener más información, consulta Roles de implementaciones sin servidores.

Funciones de usuario

Para obtener los permisos que necesitas para crear una sesión de notebook interactiva de Managed Service para Apache Spark y acceder a los recursos, pídele a tu administrador que te otorgue los siguientes roles de IAM:

  • Usa el entorno de ejecución sin servidores 2.3 o una versión anterior:
  • Usa el entorno de ejecución sin servidores 3.0 o una versión posterior: Editor de Dataproc Serverless (roles/dataproc.serverlessEditor) en el proyecto
  • Lee el controlador de JDBC desde Cloud Storage con las credenciales del usuario final: Visualizador de objetos de almacenamiento (roles/storage.objectViewer) en el bucket que contiene el controlador
  • Lee el secreto de la clave privada de Secret Manager con las credenciales del usuario final: Descriptor de acceso a secretos de Secret Manager (roles/secretmanager.secretAccessor) en el secreto o proyecto

Roles de la cuenta de servicio

Otorga los siguientes roles a la cuenta de servicio que ejecuta tu carga de trabajo. Los entornos de ejecución sin servidores 3.0 y posteriores de Managed Service para Apache Spark necesitan estos roles solo si la carga de trabajo se ejecuta con credenciales de cuenta de servicio en lugar de las credenciales de usuario final (EUC) predeterminadas.

Para garantizar que la cuenta de servicio predeterminada de Compute Engine o una cuenta de servicio personalizada tengan los permisos necesarios para ejecutar cargas de trabajo de Managed Service para Apache Spark, leer el controlador y acceder a los secretos, pídele a tu administrador que otorgue los siguientes roles de IAM a la cuenta de servicio predeterminada de Compute Engine o a una cuenta de servicio personalizada:

Requisitos previos de Workday

Antes de conectarte a Workday con Live Data Query, completa la siguiente configuración:

  1. Descarga el controlador de JDBC de Workday Live Data Query desde Workday.

  2. Sube el archivo JAR del controlador JDBC descargado a un bucket de Cloud Storage en tu proyecto.

  3. Completa los pasos de configuración para establecer la consulta de datos en vivo en tu inquilino de Workday, como se describe en la documentación de la consulta de datos en vivo de Workday.

    Durante la configuración en Workday, crea un usuario del sistema de integración (ISU), registra un cliente de API y genera un par de claves privadas.

  4. Toma nota de los siguientes valores de configuración de Workday:

    • Host de Workday: Es el host de tu usuario de Workday, por ejemplo, services1.workday.com.

    • Nombre del usuario: Es el nombre del usuario de Workday.

    • ID de cliente: Es el ID de cliente de API registrado de tu usuario de Workday.

    • Nombre de usuario de ISU: Es el nombre de usuario del sistema de integración.

Almacena la clave privada en Secret Manager

Almacena el archivo de clave privada generado durante la configuración de Workday Live Data Query de forma segura en Secret Manager:

  1. En Cloud Shell, ejecuta el siguiente comando para generar un par de claves x509:

    openssl req -x509 -newkey rsa:2048 -keyout private-key.pem -out public-key.cert -sha256 -days 365 -nodes
    
  2. Para ver la clave privada, ejecuta el siguiente comando:

    cat private-key.pem
    
  3. Almacena la clave privada en Secret Manager:

    1. En la consola de Google Cloud , ve a la página Secret Manager:

      Ir a Secret Manager

    2. Haz clic en Crear secreto.

    3. En el campo Nombre, ingresa un nombre para el Secret, como workday-private-key.

    4. En Valor del Secret, sube private-key.pem o pega el contenido de la clave privada, incluidas las líneas de encabezado y pie de página -----BEGIN PRIVATE KEY----- y -----END PRIVATE KEY-----.

    5. Haz clic en Crear secreto.

  4. Para ver la clave pública, ejecuta el siguiente comando:

    cat public-key.cert
    
  5. En Workday, busca Create x509 Public Key, pega la clave pública de public-key.cert y haz clic en OK.

  6. En el cliente de la API de Workday que creaste antes, actualiza el certificado x509 a la nueva clave x509.

Configura el Data Agent Kit en tu IDE

Puedes configurar el Data Agent Kit instalando la extensión en Visual Studio Code o en otro IDE compatible, o bien usando la extensión preinstalada en el editor de Cloud Shell.

Para configurar el Data Agent Kit en tu IDE o en el editor de Cloud Shell, completa los siguientes pasos:

  1. Establece y configura el Data Agent Kit:

    1. Instala la extensión Data Agent Kit.

    2. Configura el Data Agent Kit.

Crear un notebook

Con Data Agent Kit, crea un notebook de PySpark interactivo:

  1. En tu IDE o en el editor de Cloud Shell, abre el panel Data Agent Kit.

  2. En Apache Spark, selecciona Nuevo notebook y, luego, Kernel local.

  3. Selecciona un entorno de ejecución de la lista de entornos de ejecución disponibles (también llamados plantillas de sesión).

  4. Selecciona Comenzar con un cuaderno nuevo.

    Se abrirá un notebook nuevo con una celda inicial que contiene el código de inicialización de la sesión de Spark Connect.

  5. En la parte superior del editor de notebooks, haz clic en Select Kernel y, luego, selecciona un kernel de Python local para tu notebook.

Consulta datos de Workday en PySpark

  1. En la primera celda del notebook, instala las bibliotecas cliente necesarias y configura las variables de entorno:

    %pip install dataproc-spark-connect google-cloud-dataproc google-cloud-secret-manager google-cloud-storage
    
    #@title Set up all environment variables
    
    # Replace with your Project ID
    %env PROJECT_ID=PROJECT_ID
    
    # Replace with the name of the Secret Manager global secret in the project
    %env SECRET_NAME=workday-private-key
    # Replace with the version of the secret to use
    %env SECRET_VERSION=latest
    
    # Replace with the Cloud Storage bucket where you have the Workday Data Cloud JDBC Driver file stored
    %env JDBC_DRIVER_GCS_BUCKET=BUCKET_NAME
    # Replace with the name of the Workday Data Cloud JDBC Driver file in the Cloud Storage bucket
    %env JDBC_DRIVER_FILE_NAME=ldq-jdbc-driver-1.1.0-all.jar
    # Replace with the local directory of the notebook to copy the JDBC Driver File to
    %env JDBC_DRIVER_LOCAL_DIRECTORY=/tmp
    # Replace with the Driver Class for the Workday Data Cloud JDBC Driver
    %env WORKDAY_DRIVER_CLASS=com.workday.ldq.jdbc.Driver
    
    # ------------------------------------------------------------------------------
    
    # Replace with the Workday URL of your tenant
    %env WORKDAY_HOST=WORKDAY_HOST
    # Replace with your Workday tenant name
    %env TENANT_NAME=TENANT_NAME
    # Replace with the Client ID of the "API Client"
    %env CLIENT_ID=CLIENT_ID
    # Replace with the Integration System User username
    %env ISU_USERNAME=ISU_USERNAME
    
  2. En una celda nueva, otorga el rol de Usuario con acceso a secretos de Secret Manager (roles/secretmanager.secretAccessor) a la cuenta de servicio predeterminada de Compute Engine:

    %%bash
    COMPUTE_ENGINE_DEFAULT_SERVICE_ACCOUNT=$(gcloud iam service-accounts list --project="${PROJECT_ID}" \
      --filter="email ~ -compute@developer.gserviceaccount.com" \
      --format="value(email)")
    
    echo "COMPUTE_ENGINE_DEFAULT_SERVICE_ACCOUNT: ${COMPUTE_ENGINE_DEFAULT_SERVICE_ACCOUNT}"
    
    gcloud secrets add-iam-policy-binding ${SECRET_NAME} \
      --project="${PROJECT_ID}" \
      --member="serviceAccount:${COMPUTE_ENGINE_DEFAULT_SERVICE_ACCOUNT}" \
      --role="roles/secretmanager.secretAccessor"
    
  3. En una celda nueva, copia el controlador JDBC de Cloud Storage al directorio local:

    gsutil cp gs://$JDBC_DRIVER_GCS_BUCKET/$JDBC_DRIVER_FILE_NAME $JDBC_DRIVER_LOCAL_DIRECTORY
    
  4. En una celda nueva, instala la biblioteca cliente de Secret Manager:

    %%bash
    pip install google-cloud-secret-manager
    
  5. En una celda nueva, verifica que el archivo JAR del controlador se descargue de forma local:

    !gsutil cp gs://$JDBC_DRIVER_GCS_BUCKET/$JDBC_DRIVER_FILE_NAME /tmp/
    !ls -lh /tmp/ldq-jdbc-driver-1.1.0-all.jar
    
  6. En una celda nueva, inserta el JAR del controlador de Workday en el directorio de JAR de PySpark:

    %%bash
    
    echo "Downloading Workday JAR from Cloud Storage..."
    # Downloads your specific 1.1.0 driver JAR into the notebook's /tmp folder
    gcloud storage cp gs://$JDBC_DRIVER_GCS_BUCKET/$JDBC_DRIVER_FILE_NAME /tmp/
    
    echo "Dynamically finding the PySpark jars directory..."
    PYSPARK_JARS=$(python -c "import os, pyspark; print(os.path.join(os.path.dirname(pyspark.__file__), 'jars'))")
    echo "Found PySpark jars at: $PYSPARK_JARS"
    
    echo "Injecting Workday driver into PySpark core..."
    cp /tmp/$JDBC_DRIVER_FILE_NAME "$PYSPARK_JARS/"
    
    echo "Success! The driver is now a native part of PySpark."
    
  7. En una celda nueva, configura el entorno de Spark y recupera la clave privada x509 de Secret Manager:

    #@title Configure the Spark environment and retrieve the x509 private key from Secret Manager
    
    import os
    import pyspark
    from pyspark.sql import SparkSession
    from google.cloud import secretmanager
    
    PROJECT_ID = os.environ["PROJECT_ID"]
    SECRET_NAME = os.environ["SECRET_NAME"]
    SECRET_VERSION = os.environ["SECRET_VERSION"]
    JDBC_DRIVER_LOCAL_DIRECTORY = os.environ["JDBC_DRIVER_LOCAL_DIRECTORY"]
    JDBC_DRIVER_FILE_NAME = os.environ["JDBC_DRIVER_FILE_NAME"]
    LOCAL_JAR_PATH = JDBC_DRIVER_LOCAL_DIRECTORY + "/" + JDBC_DRIVER_FILE_NAME
    WORKDAY_HOST = os.environ["WORKDAY_HOST"]
    TENANT_NAME = os.environ["TENANT_NAME"]
    CLIENT_ID = os.environ["CLIENT_ID"]
    ISU_USERNAME = os.environ["ISU_USERNAME"]
    WORKDAY_DRIVER_CLASS = os.environ["WORKDAY_DRIVER_CLASS"]
    
    jdbc_url = f"jdbc:workday://{WORKDAY_HOST}:443/system/information_schema?SSLVerification=CA"
    
    def access_private_key_secret():
        print(f"Fetching secret contents from Secret Manager: {SECRET_NAME}...")
        client = secretmanager.SecretManagerServiceClient()
        secret_name = f"projects/{PROJECT_ID}/secrets/{SECRET_NAME}/versions/{SECRET_VERSION}"
        response = client.access_secret_version(request={"name": secret_name})
        print(f"Fetched secret contents from Secret Manager: {SECRET_NAME}")
        return response.payload.data.decode("UTF-8")
    
    private_key_content = access_private_key_secret()
    
  8. En una celda nueva, inicializa la sesión de Spark con la configuración de classpath:

    # Stop the old cached Spark session so your newly downloaded JAR is not ignored!
    try:
        spark.stop()
        print("Stopped existing Spark session.")
    except Exception:
        pass
    
    print("Initializing fresh Spark session with Classpath configuration...")
    print(f"Loading JAR from: {LOCAL_JAR_PATH}")
    
    # Rebuild Spark session with explicit Driver & Executor classpaths
    spark = SparkSession.builder \
        .appName("WorkdayJDBC Connection Example") \
        .config("spark.jars", LOCAL_JAR_PATH) \
        .config("spark.driver.extraClassPath", LOCAL_JAR_PATH) \
        .config("spark.executor.extraClassPath", LOCAL_JAR_PATH) \
        .getOrCreate()
    print("Spark Session successfully booted with JAR!")
    
  9. En una celda final, inicia la conexión y consulta Workday:

    import os
    import subprocess
    import zipfile
    from pyspark.sql import SparkSession
    
    LOCAL_JAR_PATH = "/tmp/ldq-jdbc-driver-1.1.0-all.jar"
    
    # Load bucket and file name from your Cell 1 environment variables
    GCS_BUCKET = os.environ.get("JDBC_DRIVER_GCS_BUCKET", "BUCKET_NAME")
    GCS_FILE = os.environ.get("JDBC_DRIVER_FILE_NAME", "ldq-jdbc-driver-1.1.0-all.jar")
    GCS_URI = f"gs://{GCS_BUCKET}/{GCS_FILE}"
    
    # 1. Ensure the JAR file is in the notebook's /tmp directory
    if not os.path.exists(LOCAL_JAR_PATH):
        print(f"Downloading {GCS_URI} to {LOCAL_JAR_PATH}...")
        subprocess.run(["gsutil", "cp", GCS_URI, LOCAL_JAR_PATH], check=True)
    print(f"JAR verified on disk: {LOCAL_JAR_PATH} ({os.path.getsize(LOCAL_JAR_PATH):,} bytes)")
    
    # 2. Read the real JDBC driver class name (skipping any '#' comment lines!)
    with zipfile.ZipFile(LOCAL_JAR_PATH, "r") as z:
        raw_lines = (
            z.read("META-INF/services/java.sql.Driver")
            .decode("utf-8")
            .splitlines()
        )
        # Filter out empty lines and '#' comment lines
        valid_classes = [
            line.strip()
            for line in raw_lines
            if line.strip() and not line.strip().startswith("#")
        ]
        driver_class = valid_classes[0]
    
    print(f"Real Driver Class inside JAR: {driver_class}")
    
    # 3. Get or create the Spark session
    spark = SparkSession.builder.appName("WorkdayJDBC Connection Example").getOrCreate()
    
    # 4. Inject the JAR directly into the running Java URLClassLoader (and Scala SparkContext)
    jvm = spark.sparkContext._jvm
    jar_url = jvm.java.io.File(LOCAL_JAR_PATH).toURI().toURL()
    
    # Add to both the Spark classloader and the current thread's context classloader
    jvm.org.apache.spark.util.Utils.getContextOrSparkClassLoader().addURL(jar_url)
    jvm.java.lang.Thread.currentThread().getContextClassLoader().addURL(jar_url)
    spark.sparkContext._jsc.sc().addJar(LOCAL_JAR_PATH)
    
    # Register the driver class with Spark's JDBC DriverRegistry
    jvm.org.apache.spark.sql.execution.datasources.jdbc.DriverRegistry.register(driver_class)
    print(f"Successfully registered {driver_class} in Spark's live JVM!")
    
    # 5. Query Workday
    print("Querying Workday...")
    df_data = (
        spark.read.format("jdbc")
        .option("driver", driver_class)
        .option("url", jdbc_url)
        .option("wd.authn.clientId", CLIENT_ID)
        .option("wd.authn.isu", ISU_USERNAME)
        .option(
            "wd.authn.accessTokenEndpoint",
            f"https://{WORKDAY_HOST}/ccx/oauth2/{TENANT_NAME}/token",
        )
        .option("wd.authn.privateKey", private_key_content)
        .option("query", "SELECT * FROM system.jdbc.catalogs")
        .load()
    )
    
    print("Connection Successful! Data Retrieved:")
    df_data.show(50, truncate=False)
    

    Reemplaza lo siguiente:

    • PROJECT_ID: Es el ID del proyecto de Google Cloud .
    • LOCATION: Es la región de Google Cloud tu plantilla de sesión de Managed Service para Apache Spark, por ejemplo, us-central1.
    • RUNTIME_ID: Es el ID de la plantilla de sesión de Managed Service para Apache Spark.
    • BUCKET_NAME: Es el nombre del bucket de Cloud Storage que contiene el controlador JDBC de Workday.
    • PATH/workday-live-data-query-jdbc-driver.jar: Es la ruta de acceso del objeto al JAR del controlador JDBC de Workday en tu bucket de Cloud Storage.
    • WORKDAY_HOST: Es el host de tu usuario de Workday, por ejemplo, services1.workday.com.
    • TENANT_NAME: Es el nombre de tu usuario de Workday.
    • CLIENT_ID: Es el ID de cliente de la API registrado de tu usuario de Workday.
    • ISU_USERNAME: el nombre de usuario del usuario del sistema de integración de tu inquilino de Workday.
  10. Haz clic en Ejecutar celda (el ícono de reproducción) junto a la celda o presiona Mayúsculas + Intro.

    Managed Service para Apache Spark ejecuta la consulta y muestra el resultado del DataFrame de Workday debajo de la celda.

Realiza una limpieza

Para evitar que se apliquen cargos a tu cuenta de Google Cloud por los recursos que usaste en esta guía, finaliza las sesiones interactivas activas o borra los recursos creados.

Finalizar sesiones interactivas

  1. En tu IDE o editor de Cloud Shell, finaliza la sesión activa del notebook cuando termine tu carga de trabajo.

  2. Opcional: Borra el bucket de Cloud Storage o el archivo JAR del controlador de JDBC si ya no los necesitas.

  3. Opcional: Borra el secreto de Secret Manager si ya no lo necesitas:

    gcloud secrets delete workday-private-key
    

¿Qué sigue?