Accedi ai dati di Workday con Spark

Managed Service for Apache Spark ti consente di eseguire query e analizzare i dati aziendali esterni direttamente dai tuoi workload Spark. Puoi utilizzare il driver JDBC Workday Live Data Query per connetterti al tuo tenant Workday, caricare i set di dati Workday in tempo reale in Spark DataFrame e integrare questi dati nella tua pipeline di analisi su Google Cloud.

In questa guida configurerai Workday Live Data Query, archivierai la tua chiave privata in modo sicuro in Secret Manager e utilizzerai l'estensione Google Cloud Data Agent Kit per eseguire un notebook PySpark in Visual Studio Code o nell'editor di Cloud Shell su Managed Service for Apache Spark.

Costi

L'estensione Data Agent Kit è disponibile senza costi aggiuntivi. Tuttavia, questa guida utilizza i seguenti componenti fatturabili di Google Cloud:

Per generare una stima dei costi in base all'utilizzo previsto, utilizza il calcolatore prezzi.

Prima di iniziare

  1. 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

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

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

  4. 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

Ruoli IAM (Identity and Access Management) richiesti

Per eseguire gli esempi in questa pagina sono necessari determinati ruoli IAM. A seconda delle policy dell'organizzazione, questi ruoli potrebbero essere già stati concessi. Per controllare le concessioni dei ruoli, consulta Devi concedere i ruoli?. Per saperne di più sulla concessione dei ruoli, consulta Gestisci l'accesso a progetti, cartelle e organizzazioni.

I ruoli necessari dipendono dalla modalità di esecuzione del workload. I runtime serverless di Managed Service for Apache Spark serverless 2.3 e versioni precedenti eseguono i workload come account di servizio. I runtime serverless di Managed Service for Apache Spark 3.0 e versioni successive eseguono i workload per impostazione predefinita con le credenziali dell'utente finale (EUC), quindi concedi i ruoli di accesso ai dati al tuo account utente anziché a un account di servizio. Se specifichi un service account personalizzato per un runtime 3.0 o versioni successive, il workload viene eseguito con le credenziali dell'account di servizio. Per saperne di più, consulta Ruoli dei deployment serverless.

Ruoli utente

Per ottenere le autorizzazioni necessarie per creare una sessione di blocco note interattivo di Managed Service for Apache Spark e accedere alle risorse, chiedi all'amministratore di concederti i seguenti ruoli IAM:

  • Utilizza il runtime serverless 2.3 o versioni precedenti:
  • Utilizza il runtime serverless 3.0 o versioni successive: Dataproc Serverless Editor (roles/dataproc.serverlessEditor) sul progetto
  • Leggere il driver JDBC da Cloud Storage con le credenziali dell'utente finale: Storage Object Viewer (roles/storage.objectViewer) sul bucket contenente il driver
  • Leggere il secret della chiave privata da Secret Manager con le credenziali dell'utente finale: Secret Manager Secret Accessor (roles/secretmanager.secretAccessor) sul secret o sul progetto

Ruoli del service account

Concedi i seguenti ruoli al account di servizio che esegue il tuo workload. I runtime serverless di Managed Service for Apache Spark 3.0 e versioni successive richiedono questi ruoli solo se il workload viene eseguito con le credenziali del account di servizio anziché con le credenziali dell'utente finale (EUC) predefinite.

Per assicurarti che il account di servizio predefinito di Compute Engine o un account di servizio personalizzato disponga delle autorizzazioni necessarie per eseguire i workload di Managed Service for Apache Spark, leggere il driver e accedere ai secret, chiedi all'amministratore di concedere i seguenti ruoli IAM al account di servizio predefinito di Compute Engine o a un account di servizio personalizzato:

  • Utilizza il runtime serverless 2.3 o versioni precedenti: Dataproc Worker (roles/dataproc.worker) sul progetto
  • Utilizza il runtime serverless 3.0 o versioni successive con le credenziali del account di servizio anziché con le credenziali dell'utente finale (EUC) predefinite:
  • Leggere il driver JDBC da Cloud Storage: Storage Object Viewer (roles/storage.objectViewer) sul bucket contenente il driver
  • Leggere il secret della chiave privata da Secret Manager: Secret Manager Secret Accessor (roles/secretmanager.secretAccessor) sul secret o sul progetto

Prerequisiti di Workday

Prima di connetterti a Workday utilizzando Live Data Query, completa la seguente configurazione:

  1. Scarica il driver JDBC di Workday Live Data Query da Workday.

  2. Carica il file JAR del driver JDBC scaricato in un bucket Cloud Storage nel tuo progetto.

  3. Completa i passaggi di configurazione per impostare Live Data Query nel tuo tenant Workday, come descritto nella documentazione di Workday Live Data Query.

    Durante la configurazione in Workday, crea un utente del sistema di integrazione (ISU), registra un client API e genera una coppia di chiavi private.

  4. Prendi nota dei seguenti valori di configurazione di Workday:

    • Host Workday: l'host del tenant Workday, ad esempio services1.workday.com.

    • Nome tenant: il nome del tenant di Workday.

    • ID client: l'ID client API registrato dal tuo tenant Workday.

    • Nome utente ISU: il nome utente dell'utente del sistema di integrazione.

Archivia la chiave privata in Secret Manager

Archivia in modo sicuro il file della chiave privata generato durante la configurazione di Workday Live Data Query in Secret Manager:

  1. In Cloud Shell, esegui questo comando per generare una coppia di chiavi x509:

    openssl req -x509 -newkey rsa:2048 -keyout private-key.pem -out public-key.cert -sha256 -days 365 -nodes
    
  2. Per visualizzare la chiave privata, esegui questo comando:

    cat private-key.pem
    
  3. Archivia la chiave privata in Secret Manager:

    1. Nella console Google Cloud , vai alla pagina Secret Manager:

      Vai a Secret Manager

    2. Fai clic su Crea secret.

    3. Nel campo Nome, inserisci un nome per il secret, ad esempio workday-private-key.

    4. In Valore secret, carica private-key.pem o incolla i contenuti della chiave privata, incluse le righe di intestazione e piè di pagina -----BEGIN PRIVATE KEY----- e -----END PRIVATE KEY-----.

    5. Fai clic su Crea secret.

  4. Per visualizzare la chiave pubblica, esegui questo comando:

    cat public-key.cert
    
  5. In Workday, cerca Create x509 Public Key (Crea chiave pubblica x509), incolla la chiave pubblica da public-key.cert e fai clic su OK.

  6. Nel client API Workday creato in precedenza, aggiorna il certificato x509 con la nuova chiave x509.

Configura il Data Agent Kit nel tuo IDE

Puoi configurare il Data Agent Kit installando l'estensione in Visual Studio Code o in un altro IDE supportato oppure utilizzando l'estensione preinstallata nell'editor di Cloud Shell.

Per configurare il Data Agent Kit nel tuo IDE o nell'editor di Cloud Shell, completa i seguenti passaggi:

  1. Configura il Data Agent Kit:

    1. Installa l'estensione Data Agent Kit.

    2. Configura Data Agent Kit.

Crea un notebook

Utilizzando il Data Agent Kit, crea un notebook PySpark interattivo:

  1. Nell'IDE o nell'editor di Cloud Shell, apri il riquadro Data Agent Kit.

  2. In Apache Spark, seleziona Nuovo notebook, quindi Kernel locale.

  3. Seleziona un runtime dall'elenco dei runtime disponibili (chiamati anche template di sessione).

  4. Seleziona Inizia con un nuovo notebook.

    Si apre un nuovo blocco note con una cella iniziale compilata con il codice di inizializzazione della sessione di Spark Connect.

  5. Nella parte superiore dell'editor di notebook, fai clic su Seleziona kernel, quindi seleziona un kernel Python locale per il tuo notebook.

Esegui query sui dati di Workday in PySpark

  1. Nella prima cella del notebook, installa le librerie client richieste e configura le variabili di ambiente:

    %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. In una nuova cella, concedi il ruolo Secret Manager Secret Accessor (roles/secretmanager.secretAccessor) al account di servizio predefinito di Compute Engine:

    %%bash
    COMPUTE_ENGINE_DEFAULT_SERVICE_ACCOUNT=$(gcloud iam service-accounts list --project="${PROJECT_ID}" \
      --filter="email ~ -compute@" \
      --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. In una nuova cella, copia il driver JDBC da Cloud Storage alla directory locale:

    gsutil cp gs://$JDBC_DRIVER_GCS_BUCKET/$JDBC_DRIVER_FILE_NAME $JDBC_DRIVER_LOCAL_DIRECTORY
    
  4. In una nuova cella, installa la libreria client di Secret Manager:

    %%bash
    pip install google-cloud-secret-manager
    
  5. In una nuova cella, verifica che il file JAR del driver sia stato scaricato localmente:

    !gsutil cp gs://$JDBC_DRIVER_GCS_BUCKET/$JDBC_DRIVER_FILE_NAME /tmp/
    !ls -lh /tmp/ldq-jdbc-driver-1.1.0-all.jar
    
  6. In una nuova cella, inserisci il JAR del driver Workday nella directory dei jar 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. In una nuova cella, configura l'ambiente Spark e recupera la chiave privata x509 da 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. In una nuova cella, inizializza la sessione Spark con la configurazione del percorso di classe:

    # 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. In una cella finale, avvia la connessione ed esegui una query su 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)
    

    Sostituisci quanto segue:

    • PROJECT_ID: il tuo ID progetto Google Cloud .
    • LOCATION: la regione Google Cloud del template di sessione di Managed Service for Apache Spark, ad esempio us-central1.
    • RUNTIME_ID: l'ID del template di sessione di Managed Service for Apache Spark.
    • BUCKET_NAME: il nome del bucket Cloud Storage contenente il driver JDBC Workday.
    • PATH/workday-live-data-query-jdbc-driver.jar: il percorso dell'oggetto al file JAR del driver JDBC Workday nel bucket Cloud Storage.
    • WORKDAY_HOST: l'host del tenant Workday, ad esempio services1.workday.com.
    • TENANT_NAME: il nome del tuo tenant Workday.
    • CLIENT_ID: l'ID client API registrato dal tuo tenant Workday.
    • ISU_USERNAME: il nome utente dell'utente del sistema di integrazione del tuo tenant Workday.
  10. Fai clic su Esegui cella (l'icona di riproduzione) accanto alla cella o premi Maiusc+Invio.

    Managed Service for Apache Spark esegue la query e visualizza l'output del DataFrame Workday sotto la cella.

Esegui la pulizia

Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questa guida, termina le sessioni interattive attive o elimina le risorse create.

Termina sessioni interattive

  1. Nel tuo IDE o nell'editor di Cloud Shell, termina la sessione attiva del notebook al termine del workload.

  2. (Facoltativo) Elimina il bucket Cloud Storage o il file JAR del driver JDBC se non ti servono più.

  3. (Facoltativo) Elimina il secret da Secret Manager se non è più necessario:

    gcloud secrets delete workday-private-key
    

Passaggi successivi