Self-service business intelligence front-end tools hebben de laatste jaren enorm aan functionaliteit, gebruiksgemak en populariteit gewonnen. Organisaties timmeren flink aan de weg om een brede self-service community op te zetten, vaak buiten de kaders van IT. Eindgebruikers vinden het zelf vaak ook erg tof om nieuwe data skills op te doen en mooie dashboards, rapportages en ad-hoc analyses te ontwikkelen. Geef ze eens ongelijk…
Self service is mijns inziens vooral succesvol wanneer gebruik wordt gemaakt van correcte (governed) datasets. Met governed bedoel ik datasets die ‘vrijgegeven’ worden door de BI organisatie, waar reguliere verlading op plaats vindt, waar lineage en definities van gedocumenteerd zijn en de data afkomstig is van een enterprise datawarehouse.
Datasets in front-end tools worden vaak ververst door gebruik te maken van time-based schedules. Vaak zie je dan ook dat deze schedules dagelijks om 08:00u ingepland worden, allemaal tegelijk. Dit brengt als risico met zich mee dat mogelijk een verversing binnen de tool gestart wordt wanneer processen van het datawarehouse nog niet gereed zijn. Het zijn immers twee gescheiden werelden die standaard niet van elkaar bestaan afweten. Met als gevolg, incomplete en/of incorrecte data in de rapportages en handmatige opvolging nodig om deze te corrigeren.
Recent deed deze situatie zich voor in mijn werkomgeving en werd ik nieuwsgierig naar een alternatieve oplossing. Deze heb ik gevonden door gebruik te maken van de REST API van Microsoft PowerBI, de frond-end tool gebruikt in mijn omgeving. Als onderdeel van de data loads op het datawarehouse is daarmee ook het triggeren van een dataset refresh de laatste stap.
In dit artikel leg ik graag uit hoe het technisch in elkaar steekt, welke stappen je moet nemen en verwijs door naar handig leesvoer of een goed YouTube filmpje waar ik zelf veel aan heb gehad. Ik laat zien hoe de methode toegepast kan worden als onderdeel van een proces en ga in op de toegepaste authenticatie en security, een onderdeel waar ik zelf het minst thuis in ben en daarmee de meeste uitdaging in had. De scripts heb ik beschikbaar gemaakt op mijn GitHub pagina.
Tijdens het werken hieraan heb ik veel zaken uit moeten zoeken, wellicht dat dit artikel voor iemand anders van pas kan komen.
Refresh Dataset API call
Microsoft biedt dus een API aan om een dataset te verversen op basis van de guid (technisch ID) van het object in een Workspace van de PowerBI service. Deze gebruik ik dan ook in de scripts. De API verwacht twee parameters, de DatasetID (guid van de dataset) en de groupID (de guid van de Workspace). Deze kan je vinden in de URL van de dataset;
En de call naar de API is dan met de guids ingevuld;
Ik wilde de opzet niet zo maken dat de guids voor elke toepassing eerst handmatig opgezocht moeten worden. Dit kan je ook automatiseren door het op te vragen via een get request om alle workspaces of datasets te krijgen. Met deze output kan je weer de juiste op zoeken van toepassing voor jou. Dit is in seperate functies uitgewerkt. Deze functies hebben als return value de guid van hetgeen je als input hebt gegeven, mits aanwezig.
Het aanroepen van deze functies kan je dus eerst doen, voordat je de request maakt op basis van DatasetId en GroupID. De kern van het script is eigenlijk de volgende functie, waarin je ziet dat eerst andere functies worden aangeroepen voordat de Refresh Dataset request gemaakt wordt.
Authenticatie & security
Authenticatie op de REST API gebeurd door middels van specifieke systeem accounts; de service principals. Deze service principals zijn accounts beschikbaar in Azure AD en hebben een client_id (een guid) en een client_secret (token). De permission scope voor deze service principals voor PowerBI zijn dataset.readwrite_ALL. Adam Saxton (bekend van het YouiTube kanaal Guy In a Cube) heeft een goed filmpje gemaakt waarin dit uitgelegd wordt. Daarnaast helpt deze documentatie van Microsoft ook zeker.
De service principal accounts dienen ook als admin toegevoegd te worden aan de PowerBI workspaces waarin de dataset(s) staan die je wilt gaan beheren met deze methode. Ook moet de PowerBI tennant Admin toegang verlenen voor de service princpals om gebruik te mogen maken van de API:
Hier ook een blog artikel van Microsoft zelf waarin dit verder uitgelegd staat.
Gebruik van service principals in scripts
Er zijn diverse methodes die je kan gebruiken om de secrets van een service principal in scripts te gebruiken. De secrets dienen immers ergens opgeslagen te worden. Azure Key Vault is een service van Microsoft waarmee je in staat bent secure secrets op te slaan en te managen. Secrets kunnen weer via een API call opgevraagd worden. Zelf heb ik nog geen Key Vault gebruikt in mijn implementatie, maar meer een security by obscurity variant. Ik heb een .json bestandje gemaakt waar de gegevens in opgeslagen zijn. Het bestand heb ik .env.json genoemd (de ‘punt’ zodat het niet standaard zichtbaar wordt in Explorer of directory listings op unix systemen) en vervolgens zeer bepertke permissions gegeven; alleen de owner van het bestand mag lezen en schrijven (chmod 600). Onderstaand een voorbeeld:
Deze json file kan je vervolgens gemakkelijk met de json library als dictionary data object gebruiken in Python op de volgende manier;
En de credentials zijn weer te parsen naar variabelen op deze manier;
Voor authenticatie naar Azure heb ik gebruik gemaakt van de adal library. Het verkrijgen van een tijdelijke access token gebeurd op de volgende manier:
Toepassing als onderdeel van ETL/ELT proces
Er zijn meerdere manieren hoe deze werkwijze is toe te passen in processen. Je kan het bijvoorbeeld onderdeel maken van je ETL proces, als laatste stap. Ik heb een toepassing gemaakt in Informatica Data Engineering Integration (ookwel BDM – Big Data Management genoemd). De tool waarin je werkt heet Informatica Developer, voor de Powercenter kenners onder ons, de evolutie hiervan dus. Het script is overigens niet gebonden aan slechts uitvoer in een ETL proces, maar kan ook prima afgetrapt worden door een Enterprise Scheduler, of zoiets als Apache Airflow.
Als onderdeel van een Informatica Workflow heb ik een command task gemaakt die de uitvoering van het script doet;
Het script geeft net als elk Unix commando diverse outputs; standard_out (de print statements in het script bijvoorbeeld), standard_error (alle potentiele errors die het script teruggeeft) en een exit_code (0 is goed, > 0 is een error). Deze waardes kan je bijvoorbeeld weer gebruiken voor logging in een metadatasysteem voor je dataplatform. In mijn situatie ziet dat er als volgt uit;
Ik ben zeker geen doorgewinterde Python programmeur, dus het kan vast nog beter in elkaar gezet worden. Ik merk dat ik het ontzettend leuk vind om me bezig te houden met dit soort werkzaamheden. Ik hoop dat ik iemand verder opweg kan helpen en de zoektocht naar een oplossing voor time-based schedules toegankelijk maak. Als je feedback hebt op de methode of code, laat het me weten, ik leer graag weer van anderen!