Odświeżanie Power BI Dataset z poziomu Azure Data Factory

Jak zapewne wiecie datasety w Power BI mogą być odświeżane przy pomocy wbudowanego w serwis Power BI harmonogramu. W zależności czy mówimy o Premium Capacity czy też może o Shared Capacity mamy do dyspozycji określoną liczbę odświeżeń na dobę. Sam harmonogram nie jest oczywiście jedyną opcją jeśli chodzi o odświeżenie, operację tą możemy również wykonać z poziomu różnych narzędzi, które tak naprawdę wysyłają żądanie przez REST API serwisu Power BI. Dziś chciałbym powiedzieć parę słów o tym jak wysłać tego typu żądanie z poziomu Azure Data Factory czyli jednego z najpopularniejszych narzędzi chmury Azure związanych z szeroko pojętym data engineeringiem.

Zanim przejdziemy do samego ADF spójrzmy w dokumentację jak powinno wyglądać żądanie odświeżenia (link). Okazuje się, że cała operacja sprowadza się do wysłania żądania określoną metodą do określonego URL – wygląda to następująco:

POST https://api.powerbi.com/v1.0/myorg/groups/{groupId}/datasets/{datasetId}/refreshes

Pierwsze co rzuca nam się w oczy to, że całe żądanie ma być wysłane metodą POST co jest dosyć logiczne. URL też nie wygląda w jakiś niezwykły sposób, a jedyne co musimy w nim podać to identyfikator workspace’a (groupId) oraz datasetu (datasetId). Informacje te są dostępne chociażby z poziomu Powershell i dedykowanych cmdletów dla Power BI ale jeśli chcemy sobie nieco uprościć  to informacje te możemy  zdobyć wchodząc we właściwości wybranego przez nas dataset’u – wtedy też będą one na wyciągnięcie ręki dostępne w URL:

Na powyższym przykładzie możemy zobaczyć, że identyfikator występujący po “groups” odnosi się do workspace, a ten występujący po “datasets” jest właśnie identyfikatorem naszego zestawu danych. Mamy zatem wszystkie informacje potrzebne do zbudowania żądania teraz zastanówmy się w jaki sposób uwierzytelnimy się do serwisu Power BI.

Aby to zrobić możemy posłużyć się jednym z dwóch sposobów tzn:

  • master account
  • service principal

Master account to nic innego jak zwykłe konto z uprawnieniami w określonym workspace. Konto tego typu musi mieć oczywiście przypisaną odpowiednią licencję oraz musi posiadać uprawnienia potrzebne do zrealizowania operacji odświeżenia. Tego typu podejście było i jest wykorzystywane od dosyć dawna jednak posiada kilka wad. Pierwszą z nich jest samo przypisanie licencji co wiąże się z dodatkowym kosztem. Możemy wyobrazić sobie sytuacje, że mamy pewne procedury bezpieczeństwa gdzie dla określonych workspace mają dostęp tylko określone konta, a więc będziemy musieli stworzyć N kont do odświeżania danych co może być już pokaźną pozycją w naszym budżecie. Warto również wspomnieć, że konto tego typu musi być traktowane w odpowiedni sposób np. nie może mieć włączonego Multi Factor Authentication w Azure Active Directory, a jego hasło powinno być odpowiednio rotowane i aktualizowane co w niektórych scenariuszach może być barierą nie do przejścia.

Nieco innym podejściem jest wykorzystanie obiektu typu Service Principal czyli tożsamości w AAD, która może zostać przypisana do do naszego skryptu odświeżającego. Obiekt tego typu nie wymaga przypisania do niego licencji i jest obiektem dedykowanym do tego typu operacji. Z tego też powodu serdecznie polecam wykorzystywać Service Principal wszędzie tam gdzie to tylko możliwe.

Tworzenie Service Principal’a w AAD jest stosunkowo proste i może być wykonane w dwóch różnych miejscach. Pierwszym sposobem jest oczywiście portal Azure i wykorzystanie apletu App registration:

Drugim jest Power BI Registration Tool, który prowadzi nas właściwie do tego samego jednakże interfejs wprowadzania danych jest przystosowany do ekosystemu Power BI:

Proces rejestracji jest dosyć dobrze opisany w dokumentacji i do niej odsyłam (link).

Mając już Service Principala możemy wejść do ustawień tenanta i tam w sekcji Tenant settings dopuścić użycie Service Principali do interakcji z tym tenantem:

Dodatkowo na powyższym obrazku możecie zobaczyć, że możemy wskazać grupę bezpieczeństwa do której możemy dodać nasze SP tak aby zarządzać dostępem na nieco bardziej granularnym poziomie. Jak mamy wszystko ustawione po stronie tenanta możemy wejść do wybranego Workspace i dodać naszego principala tak jak każdego normalnego użytkownika.

Przechodząc dalej przejdźmy do właściwej części niniejszego artykułu i przełączmy się do Azure Data Factory gdzie stworzymy sobie pipeline, który odświeży nasz zestaw danych. Do tego celu wykorzystamy aktywność Web Request, którą nazwiemy sobie ACT_GEN_WEB_RefreshPowerBIDataset. Kluczowa dla działania tego elementu jest zakładka Settings:

Mamy tutaj kilka rzeczy do uzupełnienia:

  • URL – adres żądania wskazany we wstępie niniejszego artykułu,
  • Method – metoda jaką ma być wysłane żądanie,
  • Headers – opcjonalne wartości wysyłane w żądaniu,
  • Body – opcjonalne ciało żądania w postaci JSON,
  • Datasets – referencja do datasetu w ADF,
  • Linked services – referencja do Linked service w ADF,
  • Integration runtime – środowisko uruchomieniowe na którym ma być uruchomione to zadanie ,
  • Disable certificate validation – możliwość wyłączenia walidacji certyfikatu,
  • Authentication – sposób autentykacji do REST API, mamy tu kilka możliwości w tym Service Principal
  • Tenant – identyfikator tenanta
  • Service principal ID – jeśli wybraliśmy Service Principal to musimy podać jego Id,
  • Service principal credential type – sposób uwierzytelnienia SP, którym może być certyfikat lub secret,
  • Service principal certificate/secret – możliwość podania certyfikatu lub sekretu dla SP (ewentualnie pobranie go z Azure Key Vault)
  • Resource – identyfikator zasobu do którego się odwołujemy.

Jak widać opcji do wypełnienia mamy naprawdę sporo. Poniżej opcje jakie ja ustawiłem w moim przypadku:

  • URL w moim przypadku jest to wyrażenie składające adres z parametrów do których będę podawał identyfikator workspace i dataset:
@concat('https://api.powerbi.com/v1.0/myorg/groups/','pipeline().parameters.__paramWorkspaceId','/datasets/',pipeline().parameters.__paramDataSetId,'/refreshes')
  • Method to zgodnie z dokumentacją POST,
  • Body – musimy tutaj przekazać pustego JSONa czyli {} jednakże z jakiegoś powodu ADF nie chciał mi takiej wartości zapisać dlatego użyłem wyrażenia:
@concat('{','}')
  • Authentication – Service Principal
  • Tenant – identyfikator tenanta, który z łatwością odnajdziemy w AAD na zakładce Overview:
  • Service Principal ID – identyfikator service principala czyli tzw. application/client id. Aby poznać ten identyfikator należy wyszukać aplet App registrations:

Następnie odszukać Service Principala, którego stworzyliśmy lub którego chcemy użyć do odświeżania i tam bez problemu odnajdziemy interesujący nas identyfikator:

  • W dalszej kolejności musimy podać wartość uwierzytelniającą dla naszego SP. W zależności od potrzeb jako metodę uwierzytelnienia  możemy podać sekret lub certyfikat – bez względu na wybraną metodą warto je przechowywać w Azure Key Vault ( o tym jak używać AKV z ADF pisałem tutaj).
  • Ostatnią interesującą nas opcją będzie Resource i tu dla każdej operacji wykonywanej na REST API Power BI wartość jest stała: https://analysis.windows.net/powerbi/api

Mamy zatem nasz request gotowy i nic nie stoi na przeszkodzie żeby go uruchomić podając wymagane parametry. Cała operacja wykonała się zaskakująco szybko:

Czy to, że zadanie wykonało się poprawnie oznacza, że dataset został odświeżony? Oczywiście nie! Żądanie które wysłaliśmy działa w sposób asynchroniczny tzn. w tym wypadku request został poprawnie przyjęty do realizacji ale nie wiemy jakim rezultatem się zakończył. Jeżeli nasz proces ma jedynie inicjować odświeżenie to tutaj kończy się nasza praca – jeśli jednak chcemy wiedzieć czy odświeżenie się powiodło czy też nie no to musimy przygotować dodatkowy krok.

Do sprawdzenia statusu przydatna będzie pętla Until, która co określony odcinek czasu sprawdzać będzie czy odświeżanie się zakończyło. Do jej obsłużenia stworzyłem zmienną __varStatus, która będzie przechowywać informacje o ostatnio przechowywanym statusie. Wyrażenie obsługujące pętle wygląda następująco:

@or(or(equals(variables('__varRefreshStatus'),'Completed'),equals(variables('__varRefreshStatus'),'Failed')),equals(variables('__varRefreshStatus'),'Disabled'))

Sprawdzamy zatem czy zwrócony status ma wartość Completed, Failed lub Disabled – takimi statusami może zakończyć się proces odświeżania – dopóki takowego nie ma musimy nadal sprawdzać. Oprócz tego polecam ustawić timeout po którym sprawdzanie tak czy inaczej się zakończy – w moim przypadku przewiduje, że odświeżenie nie powinno trwać dłużej niż 20 minut – niestety ta właściwość w ADF nie może być parametryzowana:

Wewnątrz pętli mamy trzy zadania:

 

Pierwsze z nich to odczekanie 30 sekund pomiędzy poszczególnymi wywołaniami pętli. Drugie zadanie to odwołanie przez REST API aby sprawdzić status ostatniego procesu odświeżającego – całość wygląda bardzo podobnie do tego co mieliśmy wyżej z tym, że używamy metody GET oraz oczywiście innego URL:

@concat('https://api.powerbi.com/v1.0/myorg/groups/',pipeline().parameters.__paramWorkspaceId,'/datasets/',pipeline().parameters.__paramDataSetId,'/refreshes?$top=1')

Dzięki temu otrzymamy bieżący status odświeżenia. Ostatnim elementem jest zadanie przypisujące do zmiennej status odczytany w poprzednim kroku – wykorzystane wyrażenie wygląda następująco:

@activity('ACT_GEN_WEB_GetRefreshStatus').output.value[0].status

W powyższym wyrażeniu odwołujemy się do poprzedniego kroku, a raczej tego co zostanie zwrócone, a następnie wybieramy z tablicy pierwszy element i jego status. Przypominam, że zmienna ta steruje pętlą dlatego zaraz po tym jak do zmiennej przypisana zostanie wartość świadcząca o sukcesie operacji lub błędzie to pętla zostanie zatrzymana i w zmiennej będziemy mieli status.

Po uruchomieniu naszego pipeline dostałem następujący następujący efekt:

Widać, że żądanie zostało przyjęte bez problemów, a pętla wywołana została tylko raz, dlaczego? A no dlatego, że odświeżenie nie trwało zbyt długo i po prostu  nie było potrzeby aby pętla kręciła się dłużej. Dla pewności, że nasza operacja przebiegła poprawnie możemy sprawdzić odświeżenie od strony portalu Power BI – historię odświeżeń znajdziemy oczywiście we właściwościach danego zestawu danych:

Jak widać powyżej moje wywołanie zakończyło się sukcesem i nie trwało zbyt długo. Jeśli chcielibyśmy rozbudować przedstawiony tutaj mechanizm np. poprzez wysyłkę maili w przypadku wystąpienia błędu lub np. odświeżenie wszystkich zestawów danych w podanym workspace to nic nie stoi na przeszkodzie i nie powinno to nikomu sprawić problemu. Wystarczy tylko wiedzieć która komenda odpowiada za jaką operację, a te wszystkie operacje znajdziemy w dokumentacji Power BI REST API (link).

Na ten moment to by było na tyle – dzięki za poświęcony czas i życzę miłego dnia!

Leave a Reply