Sdílet prostřednictvím


Jak vytvořit a aktualizovat definici úlohy Sparku pomocí rozhraní Microsoft Fabric Rest API

Rozhraní Microsoft Fabric Rest API poskytuje koncový bod služby pro operace CRUD s položkami Fabric. V tomto kurzu si projdeme kompletní scénář vytvoření a aktualizace artefaktu definice úlohy Sparku. Zahrnuje se tři základní kroky:

  1. Vytvoření položky definice úlohy Sparku s určitým počátečním stavem
  2. Nahrání hlavního definičního souboru a dalších souborů lib
  3. Aktualizujte položku definice úlohy Sparku pomocí adresy URL OneLake hlavního definičního souboru a dalších souborů lib.

Požadavky

  1. Pro přístup k rozhraní REST API fabric se vyžaduje token Microsoft Entra. Knihovna MSAL se doporučuje získat token. Další informace naleznete v tématu Podpora toku ověřování v MSAL.
  2. Pro přístup k rozhraní OneLake API se vyžaduje token úložiště. Další informace najdete v tématu MSAL pro Python.

Vytvoření položky definice úlohy Sparku s počátečním stavem

Rozhraní Microsoft Fabric Rest API definuje jednotný koncový bod pro operace CRUD s položkami infrastruktury. Koncový bod je https://api.fabric.microsoft.com/v1/workspaces/{workspaceId}/items.

Podrobnosti o položce se zadává v textu požadavku. Tady je příklad textu požadavku pro vytvoření položky definice úlohy Sparku:

{
    "displayName": "SJDHelloWorld",
    "type": "SparkJobDefinition",
    "definition": {
        "format": "SparkJobDefinitionV1",
        "parts": [
            {
                "path": "SparkJobDefinitionV1.json",
                "payload":"eyJleGVjdXRhYmxlRmlsZSI6bnVsbCwiZGVmYXVsdExha2Vob3VzZUFydGlmYWN0SWQiOiIiLCJtYWluQ2xhc3MiOiIiLCJhZGRpdGlvbmFsTGFrZWhvdXNlSWRzIjpbXSwicmV0cnlQb2xpY3kiOm51bGwsImNvbW1hbmRMaW5lQXJndW1lbnRzIjoiIiwiYWRkaXRpb25hbExpYnJhcnlVcmlzIjpbXSwibGFuZ3VhZ2UiOiIiLCJlbnZpcm9ubWVudEFydGlmYWN0SWQiOm51bGx9",
                "payloadType": "InlineBase64"
            }
        ]
    }
}

V tomto příkladu je položka definice úlohy Sparku pojmenována jako SJDHelloWorld. Pole payload je obsah kódování base64 nastavení podrobností po dekódování obsahu:

{
    "executableFile":null,
    "defaultLakehouseArtifactId":"",
    "mainClass":"",
    "additionalLakehouseIds":[],
    "retryPolicy":null,
    "commandLineArguments":"",
    "additionalLibraryUris":[],
    "language":"",
    "environmentArtifactId":null
}

Tady jsou dvě pomocné funkce pro kódování a dekódování podrobného nastavení:

import base64

def json_to_base64(json_data):
    # Serialize the JSON data to a string
    json_string = json.dumps(json_data)
    
    # Encode the JSON string as bytes
    json_bytes = json_string.encode('utf-8')
    
    # Encode the bytes as Base64
    base64_encoded = base64.b64encode(json_bytes).decode('utf-8')
    
    return base64_encoded

def base64_to_json(base64_data):
    # Decode the Base64-encoded string to bytes
    base64_bytes = base64_data.encode('utf-8')
    
    # Decode the bytes to a JSON string
    json_string = base64.b64decode(base64_bytes).decode('utf-8')
    
    # Deserialize the JSON string to a Python dictionary
    json_data = json.loads(json_string)
    
    return json_data

Tady je fragment kódu pro vytvoření položky definice úlohy Sparku:

import requests

bearerToken = "breadcrumb"; # replace this token with the real AAD token

headers = {
    "Authorization": f"Bearer {bearerToken}", 
    "Content-Type": "application/json"  # Set the content type based on your request
}

payload = "eyJleGVjdXRhYmxlRmlsZSI6bnVsbCwiZGVmYXVsdExha2Vob3VzZUFydGlmYWN0SWQiOiIiLCJtYWluQ2xhc3MiOiIiLCJhZGRpdGlvbmFsTGFrZWhvdXNlSWRzIjpbXSwicmV0cnlQb2xpY3kiOm51bGwsImNvbW1hbmRMaW5lQXJndW1lbnRzIjoiIiwiYWRkaXRpb25hbExpYnJhcnlVcmlzIjpbXSwibGFuZ3VhZ2UiOiIiLCJlbnZpcm9ubWVudEFydGlmYWN0SWQiOm51bGx9"

# Define the payload data for the POST request
payload_data = {
    "displayName": "SJDHelloWorld",
    "Type": "SparkJobDefinition",
    "definition": {
        "format": "SparkJobDefinitionV1",
        "parts": [
            {
                "path": "SparkJobDefinitionV1.json",
                "payload": payload,
                "payloadType": "InlineBase64"
            }
        ]
    }
}

# Make the POST request with Bearer authentication
sjdCreateUrl = f"https://api.fabric.microsoft.com//v1/workspaces/{workspaceId}/items"
response = requests.post(sjdCreateUrl, json=payload_data, headers=headers)

Nahrání hlavního definičního souboru a dalších souborů lib

K nahrání souboru do OneLake se vyžaduje token úložiště. Tady je pomocná funkce pro získání tokenu úložiště:


import msal

def getOnelakeStorageToken():
    app = msal.PublicClientApplication(
        "{client id}", # this filed should be the client id 
        authority="https://login.microsoftonline.com/microsoft.com")

    result = app.acquire_token_interactive(scopes=["https://storage.azure.com/.default"])

    print(f"Successfully acquired AAD token with storage audience:{result['access_token']}")

    return result['access_token']

Teď máme vytvořenou položku definice úlohy Sparku, abychom ji mohli spustit, musíme nastavit hlavní definiční soubor a požadované vlastnosti. Koncový bod pro nahrání souboru pro tuto položku SJD je https://onelake.dfs.fabric.microsoft.com/{workspaceId}/{sjdartifactid}. Měl by se použít stejný "workspaceId" z předchozího kroku, hodnota sjdartifactid se našla v textu odpovědi předchozího kroku. Tady je fragment kódu pro nastavení hlavního definičního souboru:

import requests

# three steps are required: create file, append file, flush file

onelakeEndPoint = "https://onelake.dfs.fabric.microsoft.com/workspaceId/sjdartifactid"; # replace the id of workspace and artifact with the right one
mainExecutableFile = "main.py"; # the name of the main executable file
mainSubFolder = "Main"; # the sub folder name of the main executable file. Don't change this value


onelakeRequestMainFileCreateUrl = f"{onelakeEndPoint}/{mainSubFolder}/{mainExecutableFile}?resource=file" # the url for creating the main executable file via the 'file' resource type
onelakePutRequestHeaders = {
    "Authorization": f"Bearer {onelakeStorageToken}", # the storage token can be achieved from the helper function above
}

onelakeCreateMainFileResponse = requests.put(onelakeRequestMainFileCreateUrl, headers=onelakePutRequestHeaders)
if onelakeCreateMainFileResponse.status_code == 201:
    # Request was successful
    print(f"Main File '{mainExecutableFile}' was successfully created in onelake.")

# with previous step, the main executable file is created in OneLake, now we need to append the content of the main executable file

appendPosition = 0;
appendAction = "append";

### Main File Append.
mainExecutableFileSizeInBytes = 83; # the size of the main executable file in bytes
onelakeRequestMainFileAppendUrl = f"{onelakeEndPoint}/{mainSubFolder}/{mainExecutableFile}?position={appendPosition}&action={appendAction}";
mainFileContents = "filename = 'Files/' + Constant.filename; tablename = 'Tables/' + Constant.tablename"; # the content of the main executable file, please replace this with the real content of the main executable file
mainExecutableFileSizeInBytes = 83; # the size of the main executable file in bytes, this value should match the size of the mainFileContents

onelakePatchRequestHeaders = {
    "Authorization": f"Bearer {onelakeStorageToken}",
    "Content-Type" : "text/plain"
}

onelakeAppendMainFileResponse = requests.patch(onelakeRequestMainFileAppendUrl, data = mainFileContents, headers=onelakePatchRequestHeaders)
if onelakeAppendMainFileResponse.status_code == 202:
    # Request was successful
    print(f"Successfully Accepted Main File '{mainExecutableFile}' append data.")

# with previous step, the content of the main executable file is appended to the file in OneLake, now we need to flush the file

flushAction = "flush";

### Main File flush
onelakeRequestMainFileFlushUrl = f"{onelakeEndPoint}/{mainSubFolder}/{mainExecutableFile}?position={mainExecutableFileSizeInBytes}&action={flushAction}"
print(onelakeRequestMainFileFlushUrl)
onelakeFlushMainFileResponse = requests.patch(onelakeRequestMainFileFlushUrl, headers=onelakePatchRequestHeaders)
if onelakeFlushMainFileResponse.status_code == 200:
    print(f"Successfully Flushed Main File '{mainExecutableFile}' contents.")
else:
    print(onelakeFlushMainFileResponse.json())

V případě potřeby nahrajte další soubory knihovny stejným postupem.

Aktualizujte položku definice úlohy Sparku pomocí adresy URL OneLake hlavního definičního souboru a dalších souborů lib.

Doteď jsme vytvořili položku definice úlohy Sparku s určitým počátečním stavem, nahráli jsme hlavní definiční soubor a další soubory lib. Posledním krokem je aktualizace položky Definice úlohy Sparku tak, aby nastavil vlastnosti ADRESY URL hlavního definičního souboru a dalších souborů lib. Koncový bod pro aktualizaci položky definice úlohy Sparku je https://api.fabric.microsoft.com/v1/workspaces/{workspaceId}/items/{sjdartifactid}. Měl by se použít stejný "workspaceId" a "sjdartifactid" z předchozích kroků. Tady je fragment kódu pro aktualizaci položky definice úlohy Sparku:


mainAbfssPath = f"abfss://{workspaceId}@onelake.dfs.fabric.microsoft.com/{sjdartifactid}/Main/{mainExecutableFile}" # the workspaceId and sjdartifactid are the same as previous steps, the mainExecutableFile is the name of the main executable file
libsAbfssPath = f"abfss://{workspaceId}@onelake.dfs.fabric.microsoft.com/{sjdartifactid}/Libs/{libsFile}"  # the workspaceId and sjdartifactid are the same as previous steps, the libsFile is the name of the libs file
defaultLakehouseId = 'defaultLakehouseid'; # replace this with the real default lakehouse id

updateRequestBodyJson = {
    "executableFile":mainAbfssPath,
    "defaultLakehouseArtifactId":defaultLakehouseId,
    "mainClass":"",
    "additionalLakehouseIds":[],
    "retryPolicy":None,
    "commandLineArguments":"",
    "additionalLibraryUris":[libsAbfssPath],
    "language":"Python",
    "environmentArtifactId":None}

# Encode the bytes as a Base64-encoded string
base64EncodedUpdateSJDPayload = json_to_base64(updateRequestBodyJson)

# Print the Base64-encoded string
print("Base64-encoded JSON payload for SJD Update:")
print(base64EncodedUpdateSJDPayload)

# Define the API URL
updateSjdUrl = f"https://api.fabric.microsoft.com//v1/workspaces/{workspaceId}/items/{sjdartifactid}/updateDefinition"

updatePayload = base64EncodedUpdateSJDPayload
payloadType = "InlineBase64"
path = "SparkJobDefinitionV1.json"
format = "SparkJobDefinitionV1"
Type = "SparkJobDefinition"

# Define the headers with Bearer authentication
bearerToken = "breadcrumb"; # replace this token with the real AAD token

headers = {
    "Authorization": f"Bearer {bearerToken}", 
    "Content-Type": "application/json"  # Set the content type based on your request
}

# Define the payload data for the POST request
payload_data = {
    "displayName": "sjdCreateTest11",
    "Type": Type,
    "definition": {
        "format": format,
        "parts": [
            {
                "path": path,
                "payload": updatePayload,
                "payloadType": payloadType
            }
        ]
    }
}


# Make the POST request with Bearer authentication
response = requests.post(updateSjdUrl, json=payload_data, headers=headers)
if response.status_code == 200:
    print("Successfully updated SJD.")
else:
    print(response.json())
    print(response.status_code)

K rekapitulace celého procesu je potřeba rozhraní REST API fabric i rozhraní OneLake API k vytvoření a aktualizaci položky definice úlohy Sparku. Rozhraní REST API prostředků infrastruktury slouží k vytvoření a aktualizaci položky definice úlohy Sparku, rozhraní OneLake API slouží k nahrání hlavního definičního souboru a dalších souborů lib. Hlavní definiční soubor a další soubory lib se nejprve nahrají do OneLake. Vlastnosti adresy URL hlavního definičního souboru a dalších souborů lib se pak nastaví v položce Definice úlohy Sparku.