{"id":475,"date":"2021-02-13T17:09:30","date_gmt":"2021-02-13T16:09:30","guid":{"rendered":"https:\/\/www.csopro.de\/biblog\/?p=475"},"modified":"2021-02-13T17:11:18","modified_gmt":"2021-02-13T16:11:18","slug":"azure-analysis-services-automatisch-pausieren","status":"publish","type":"post","link":"https:\/\/www.csopro.de\/biblog\/2021\/02\/azure-analysis-services-automatisch-pausieren\/","title":{"rendered":"Azure Analysis Services automatisch Pausieren"},"content":{"rendered":"\n<p>Bei einem meiner Kunden hatten wir mehrere Azure Analysis Services im Einsatz. Wenn die kleinsten Tarife nicht mehr ausreichen, kann das mit der Zeit eine teure Angelegenheit werden.<\/p>\n\n\n\n<p>Deshalb haben wir folgende Struktur in den Analysis Services, die in Azure gehostet werden, aufgebaut:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Jedes Projekt hat seinen eigenen Entwicklungsserver<\/li><li>Jedes Projekt hat seinen eigenen Testserver<\/li><li>Es gibt f\u00fcr die Projekte gemeinsame genutzte Produktivserver<\/li><\/ul>\n\n\n\n<p>Dabei verwenden wir bei den Entwicklungs- und Testservern den niedrigst m\u00f6glichen Tarif (in der Regel D1, B1).<\/p>\n\n\n\n<p>Dar\u00fcber sollen die Entwicklungs- und Testserver nur dann laufen und somit Geld kosten, wenn sie ben\u00f6tigt werden. Das hei\u00dft, wenn an einem Projekt gerade weder entwickelt noch getestet wird, sind die beiden betreffenden Azure Analysis Services (AAS) pausiert.<\/p>\n\n\n\n<p>Um dies nicht nur manuell durch den Entwickler umzusetzen, haben wir einen Automatismus implementiert:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Zun\u00e4chst gibt es eine relationale Tabelle, in der alle AAS aufgef\u00fchrt sind<\/li><li>F\u00fcr jeden AAS kann man definieren, bis wann er laufen soll <br>(Wenn man z.B. im Test ist, m\u00f6chte man nicht, dass der Server nachts automatisiert pausiert wird)<\/li><li>Abends l\u00e4uft ein Job (eine Data Factory Pipeline), die alle auszuschaltenden AAS pausiert, falls sie noch laufen. <\/li><\/ul>\n\n\n\n<p>Bei der Umsetzung habe ich mich vom <a rel=\"noreferrer noopener\" href=\"https:\/\/microsoft-bitools.blogspot.com\/2020\/06\/pause-and-resume-analysis-services-with.html\" target=\"_blank\">hier <\/a>zu findenden guten Artikel inspierieren lassen. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Erste Pipeline &#8222;SuspendOrResumeAAS&#8220;<\/h2>\n\n\n\n<p>Zun\u00e4chst erstelle ich eine Pipeline &#8222;SuspendOrResumeAAS&#8220;:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/SuspendOrResume_DF-1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"578\" src=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/SuspendOrResume_DF-1.png\" alt=\"\" class=\"wp-image-478\" srcset=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/SuspendOrResume_DF-1.png 960w, https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/SuspendOrResume_DF-1-300x181.png 300w, https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/SuspendOrResume_DF-1-768x462.png 768w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/a><figcaption>Pipeline SuspendOrResumeAAS<\/figcaption><\/figure>\n\n\n\n<p>Man sieht hier schon gut, woraus diese Pipeline besteht:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Es gibt 3 Parameter:<ul><li>action: Soll die AAS-Instanz pausiert (supend) oder gestartet (resume) werden?<\/li><li>aasName: Name der AAS<\/li><li>ressourceGroupName: Name der Ressourcengruppe<\/li><\/ul><\/li><li>Es gibt eine Variable (was man im Screen Shot nicht sieht):<ul><li>subscriptionId (Wir werden das sp\u00e4ter f\u00fcr den API-Aufruf ben\u00f6tigen)<\/li><\/ul><\/li><\/ul>\n\n\n\n<p>Was macht die Pipeline?<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Sie ermittelt zuerst den Status des AAS<\/li><li>Dann wird \u00fcberpr\u00fcft, ob der Status zu der Aktion passt (Man kann eine pausierte AAS nicht pausieren \ud83d\ude42 )<\/li><li>Wenn der Status OK ist, wird der API-Aufruf mit der gew\u00fcnschten Aktion durchgef\u00fchrt.<\/li><\/ul>\n\n\n\n<p>Die Schritte beleuchten wir jetzt n\u00e4her:<\/p>\n\n\n\n<p>F\u00fcr die Ermittlung des Status (<strong>infoZuAAS<\/strong>) verwenden wir eine Web-Aktivit\u00e4t:<\/p>\n\n\n\n<p>In den Einstellungen bauen wir die URL via dynamischen Inhalt zusammen:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"scala\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@concat('https:\/\/management.azure.com\/subscriptions\/', variables('subscriptionId') , '\/resourceGroups\/', pipeline().parameters.ressourceGroupName, '\/providers\/Microsoft.AnalysisServices\/servers\/', pipeline().parameters.aasName, '?api-version=2017-08-01')<\/pre>\n\n\n\n<p>Als  Methode wird &#8222;GET&#8220; eingestellt.<\/p>\n\n\n\n<p>Wie auch im zitierten Artikel vorgeschlagen, verweden wir MSI als Authentifizierung (als Ressource &#8222;https:\/\/management.azure.com\/&#8220; eintragen). <\/p>\n\n\n\n<p>Dazu m\u00fcssen wir f\u00fcr jede betreffende AAS unter &#8222;Access Control (IAM)&#8220; den Punkt &#8222;Add role assignments&#8220; ausw\u00e4hlen. Dort definieren wir als Contributor die Data Factory, in der wir unsere Pipeline erstellen:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-style-default\"><a href=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/AddRoleAssignmentDF-1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"403\" height=\"378\" src=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/AddRoleAssignmentDF-1.png\" alt=\"\" class=\"wp-image-495\" srcset=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/AddRoleAssignmentDF-1.png 403w, https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/AddRoleAssignmentDF-1-300x281.png 300w\" sizes=\"auto, (max-width: 403px) 100vw, 403px\" \/><\/a><figcaption>Add role assignment: DF als Contributor des AAS<\/figcaption><\/figure>\n\n\n\n<p>Wenn wir diese Aktivit\u00e4t im Debug-Modus starten, sehen wir <\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-style-default\"><a href=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/grafik-1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"778\" height=\"114\" src=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/grafik-1.png\" alt=\"\" class=\"wp-image-483\" srcset=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/grafik-1.png 778w, https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/grafik-1-300x44.png 300w, https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/grafik-1-768x113.png 768w\" sizes=\"auto, (max-width: 778px) 100vw, 778px\" \/><\/a><figcaption>Debuginformation zu infoZuAAS<\/figcaption><\/figure>\n\n\n\n<p>\u00dcber die Pfeile (links: Input, rechts: Output) k\u00f6nnen wir die aufrufende URL kontrollieren:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-style-default\"><a href=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/Input.png\"><img loading=\"lazy\" decoding=\"async\" width=\"434\" height=\"281\" src=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/Input.png\" alt=\"\" class=\"wp-image-486\" srcset=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/Input.png 434w, https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/Input-300x194.png 300w\" sizes=\"auto, (max-width: 434px) 100vw, 434px\" \/><\/a><figcaption>Input<\/figcaption><\/figure>\n\n\n\n<p>Unter Output sieht man:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-style-default\"><a href=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/Output.png\"><img loading=\"lazy\" decoding=\"async\" width=\"428\" height=\"282\" src=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/Output.png\" alt=\"\" class=\"wp-image-487\" srcset=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/Output.png 428w, https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/Output-300x198.png 300w\" sizes=\"auto, (max-width: 428px) 100vw, 428px\" \/><\/a><figcaption>Output<\/figcaption><\/figure>\n\n\n\n<p>Hier sehen wir unter <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">properties <\/code>&gt; <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">state <\/code>&#8222;Paused&#8220;, was hei\u00dft, dass die AAS pausiert ist. F\u00fcr eine laufende AAS ist der state &#8222;Succeeded&#8220;.<\/p>\n\n\n\n<p>Dies nutzen wir dann gleich in der If-Abfrage (<strong>isInStateForAction<\/strong>): Um den Status in der Bedingung abzufragen, kann man via Code darauf zugreifen. Mit <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">activity().output<\/code> erh\u00e4lt man den gesamten Output und kann dann im JSON \u00fcber . auf die einzelnen Attribute in der Hierarchie zugreifen:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"scala\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">activity('infoZuAAS').output.properties.state<\/pre>\n\n\n\n<p>Der gesamte Code f\u00fcr die &#8222;Expression&#8220; in der &#8222;If Condition&#8220; sieht so aus:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"scala\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@or(\nand(equals(activity('infoZuAAS').output.properties.state, 'Paused'),equals(toLower(pipeline().parameters.action), 'resume'))\n,\nand(equals(activity('infoZuAAS').output.properties.state, 'Succeeded'),equals(toLower(pipeline().parameters.action), 'suspend'))\n)<\/pre>\n\n\n\n<p>Die innere Aktivit\u00e4t ist wieder eine Web-Aktivit\u00e4t (<strong>pause or resume AAS<\/strong>):<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-style-default\"><a href=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/grafik-3.png\"><img loading=\"lazy\" decoding=\"async\" width=\"624\" height=\"569\" src=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/grafik-3.png\" alt=\"\" class=\"wp-image-488\" srcset=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/grafik-3.png 624w, https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/grafik-3-300x274.png 300w\" sizes=\"auto, (max-width: 624px) 100vw, 624px\" \/><\/a><\/figure>\n\n\n\n<p>Diese Web-Aktivit\u00e4t unterscheidet sich von der vorhergehenden in der URL, in der nun die Aktion (suspend oder resume) mit angegeben wird. Au\u00dferdem ist die Methode POST. Deshalb muss der Text mit angegeben werden &#8211; auch wenn die AAS-API das eigentlich nicht ben\u00f6tigt, weswegen wir hier<code data-enlighter-language=\"scala\" class=\"EnlighterJSRAW\"> {\"Dummy\":\"Dummy\"} <\/code>eintragen.<\/p>\n\n\n\n<p>Die URL wird mit dieser Formel definiert:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"scala\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@concat('https:\/\/management.azure.com\/subscriptions\/', variables('subscriptionId'), '\/resourceGroups\/', pipeline().parameters.ressourceGroupName, '\/providers\/Microsoft.AnalysisServices\/servers\/', pipeline().parameters.aasName, '\/' , pipeline().parameters.action, '?api-version=2017-08-01')<\/pre>\n\n\n\n<p>Authentifizierung und Ressource wird wie oben gesetzt.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Zweite Pipeline: alleAASausschalten<\/h2>\n\n\n\n<figure class=\"wp-block-image size-large is-style-default\"><a href=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/Pipeline_alleAASausschalten.png\"><img loading=\"lazy\" decoding=\"async\" width=\"549\" height=\"234\" src=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/Pipeline_alleAASausschalten.png\" alt=\"\" class=\"wp-image-490\" srcset=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/Pipeline_alleAASausschalten.png 549w, https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/Pipeline_alleAASausschalten-300x128.png 300w\" sizes=\"auto, (max-width: 549px) 100vw, 549px\" \/><\/a><figcaption>Pipeline alleAASausschalten<\/figcaption><\/figure>\n\n\n\n<p>Die Suche\/Lookup-Aktivit\u00e4t &#8222;<strong>lies Config Tabelle<\/strong>&#8220; liest per Query aus einer SQL-Server-Tabelle, welche AAS auszuschalten sind:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">SELECT AAS_Name, RessourceGroupName FROM Management.[Config_AAS_Shutdown]\nWHERE getdate() > keep_Online_Until<\/pre>\n\n\n\n<p>In der For-Each-Schleife &#8222;<strong>jedenAASausschalten<\/strong>&#8220; ist folgende Einstellung zu machen:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"scala\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@activity('lies Config Tabelle').output.value<\/pre>\n\n\n\n<p>Und innerhalb der Schleife wird eine Aktivit\u00e4t ausgef\u00fchrt:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-style-default\"><a href=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/callPipeline.png\"><img loading=\"lazy\" decoding=\"async\" width=\"489\" height=\"570\" src=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/callPipeline.png\" alt=\"\" class=\"wp-image-493\" srcset=\"https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/callPipeline.png 489w, https:\/\/www.csopro.de\/biblog\/wp-content\/uploads\/2021\/02\/callPipeline-257x300.png 257w\" sizes=\"auto, (max-width: 489px) 100vw, 489px\" \/><\/a><figcaption>die unter (1) erstellte Pipeline aufrufen<\/figcaption><\/figure>\n\n\n\n<p>Als Parameter \u00fcbergeben wir an diese Pipeline:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>action: suspend (fest definiert)<\/li><li>aasName: Formel <code data-enlighter-language=\"scala\" class=\"EnlighterJSRAW\">@item().AAS_Name<\/code><\/li><li>ressourceGroupName<code data-enlighter-language=\"scala\" class=\"EnlighterJSRAW\"> @item().RessourceGroupName<\/code><\/li><\/ul>\n\n\n\n<p>Somit m\u00fcssen wir nur noch einen Trigger t\u00e4glich um 19 Uhr definieren.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Weitere M\u00f6glichkeiten<\/h2>\n\n\n\n<p>Wir haben darauf verzichtet, einen Automatismus zu erstellen, der am Vormittag die Entwickler-Server wieder hochf\u00e4hrt.<\/p>\n\n\n\n<p>Hintergrund war, dass wir die Entwicklungs- und Testserver nicht jeden Tag brauchen. Sie schnell manuell zu starten, ist kein gro\u00dfer Aufwand &#8211; deswegen lassen wir das so.<\/p>\n\n\n\n<p>Aber nat\u00fcrlich w\u00e4re es einfach, ganz  analog eine Pipeline zu erstellen.<\/p>\n\n\n\n<p>Uns war aber wichtig, den hier vorgestellten Weg zu implementieren, da man als Entwickler schnell mal vergisst, einen AAS auszuschalten &#8211; und mit diesem Automatismus ist das kein Problem, da jede Nacht \u00fcberpr\u00fcft wird, ob die AAS aus sind &#8211; und, wenn nicht, wieder ausgeschaltet werden.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Bei einem meiner Kunden hatten wir mehrere Azure Analysis Services im Einsatz. Wenn die kleinsten Tarife nicht mehr ausreichen, kann das mit der Zeit eine teure Angelegenheit werden. Deshalb haben wir folgende Struktur in den Analysis Services, die in Azure gehostet werden, aufgebaut: Jedes Projekt hat seinen eigenen Entwicklungsserver Jedes Projekt hat seinen eigenen Testserver &hellip; <a href=\"https:\/\/www.csopro.de\/biblog\/2021\/02\/azure-analysis-services-automatisch-pausieren\/\" class=\"more-link\"><span class=\"screen-reader-text\">Azure Analysis Services automatisch Pausieren<\/span> weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[62,63,64],"tags":[67,69,68,66],"class_list":["post-475","post","type-post","status-publish","format-standard","hentry","category-azure","category-azure-anaysis-services","category-azure-data-factory","tag-aas","tag-foreach","tag-pipeline","tag-web-api"],"_links":{"self":[{"href":"https:\/\/www.csopro.de\/biblog\/wp-json\/wp\/v2\/posts\/475","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.csopro.de\/biblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.csopro.de\/biblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.csopro.de\/biblog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.csopro.de\/biblog\/wp-json\/wp\/v2\/comments?post=475"}],"version-history":[{"count":9,"href":"https:\/\/www.csopro.de\/biblog\/wp-json\/wp\/v2\/posts\/475\/revisions"}],"predecessor-version":[{"id":497,"href":"https:\/\/www.csopro.de\/biblog\/wp-json\/wp\/v2\/posts\/475\/revisions\/497"}],"wp:attachment":[{"href":"https:\/\/www.csopro.de\/biblog\/wp-json\/wp\/v2\/media?parent=475"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.csopro.de\/biblog\/wp-json\/wp\/v2\/categories?post=475"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.csopro.de\/biblog\/wp-json\/wp\/v2\/tags?post=475"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}