Hey, SAP Systems! My PowerApp says Snooze! But only if you’re ready yet
Stopping non-critical SAP systems is an integral part of any cloud practice to leverage resources efficiently in terms of capacity and cost. On top of that providing self-service on-demand start/stop capabilities to your developers empowers them. Solving this process through tickets or similar creates overhead that can be avoided.
Today I will show you how to achieve such a practice and complete the awesome blog (part 1) by my colleagues Goran Condric and Robert Biro, who showed you how to perform a graceful shutdown of HANA (or SQL) and NetWeaver VMs in Azure.
Today’s post is part 2 of the series and completes the concept.
We will have a look at a mobile-ready approach with PowerApps using cloud flows to make use of Goran’s nice Azure Automation run-books and scripts from your smartphone. With them you can start/stop and schedule any SAP system based on its SID on Azure. We use it for our internal FastTrack for Azure SAP Lab environment for instance.
This is a community effort to distribute the concept and therefore we are happy to receive feature requests via the GitHub Issues section.
Mobile phones ready?
First you need to pick your Azure subscription, which is pre-loaded via the Azure Resource Manager REST API based on your user’s available subscriptions context. Please note the SAP VM search is initiated by the dropdown change event. So, if you didn’t need to change you use the second refresh icon to start the process without an additional change.
Your selection triggers the search via the same interface within the given subscription to identify all VMs tagged with SAP SIDs. The result is shown on the list below the filter bars. For a quick overview, the meta data is stripped to show only the SID name, its location and its resource group, which is needed for the subsequent calls to our Azure Automation Account. The flow happens from left to right.
Fig.1 Screenshot of PowerApp home, detail and scheduling view from smart phone (excluding info/bug report view)
Furthermore, you get to see, who is currently using the SAP systems, how many mins are left till the automatic shutdown (46mins in our case) and in what state the last initiated automation job (start or stop) is. Be aware that I enforce user blocking on that screen for “claimed” SAP SIDs. Meaning only the person, who started it can stop it before its scheduled shutdown. You might want to add “super admins” as an exception to that rule on the PowerAutomate cloud flow “StartSAPBySID”.
Since the start-up of Hana and NetWeaver usually takes a couple of minutes, it would be nice to check the SAP availability automatically too. Very often I do this from the SAPGUI directly and see if the login screen pops up. But you can also do it from the PowerApp using the refresh icon at the top right. Once the job state is on Completed your System should be live.
Ping deprecated: in favor of more efficient manual checks
Our first approach to that availability check was to add a call to the unprotected standard on SAP transaction SICF. We consider that secure, because it is only reachable from trusted sources (check further down on the Azure App Gateway setup) and it does not expose any SAP data. If you don’t like that you can still move to the protected ping service at sap/bc/ping and supply credentials. The successful response from the ping ensures SAP is ready to be hit by OData requests or to open SAPGUI.
At the time of writing this post we are investing in replacing the ping service with an standard agent on OS level, that comes with the Azure Monitor for SAP Solutions and Azure Log Analytics. That relies on the sapctrl process and will give us with the next release all the capabilities for tight integration on the availability check. So, stay tuned for the next release of our community effort 😉 Now, on to the details of the currently published implementation.
Wait what, public SAP ping service? My SAP is private!
You are right. Ours is too 😉We have a private VNet on Azure, which is only accessible from our VPN and our PowerAutomate tenant, so that we can do the ping call from the PowerApp.
Fig.2 Overview of integration architecture
We get the VM state via the Azure Resource Manager REST API, which is protected by Azure AD and limited to a specific service principal, that has access to the VM via Resource-Based-Access-Control (RBAC) only. Find more details on the setup on this Azure Docs entry.
The Azure Automation Account and Table Storage is protected by Azure AD too. The authentication on the VM is done through that are stored in the secure area of the Automation account. See more on Goran’s post.
The SAP system’s VM(s) have a private IP address only and therefore are limited to boundaries of the virtual network for inbound connections. We allow access from our Point-2-Site VPN connection or via a specific https endpoint exposed from the Azure Application Gateway (including a web application firewall for additional protection). On top of that the gateway subnet only accepts requests from the IP-range of PowerAutomate (same as Azure Logic Apps). This is done via network security groups (NSGs). You can re-use Azure’s built-in service tag (see column Source “LogicApps”) to avoid hard-coding IPs. Azure automatically reflects any IP range changes this way. Find the reference from the Azure docs here.
Table 1 Overview of NSG rules to restrict access to SAP from PowerAutomate only
The PowerPlatform is protected again by Azure AD with RBAC on the power app and the logic on PowerAutomate. The owner/admin of the app may share it with groups governed by Azure AD as you can see below.
Fig.3 Screenshot share PowerApp
Note the warning, that implicitly shared connections on the cloud flow will be exposed to the people you share this app with. You may think of isolating the Table storage that causes this remark. However, it stores only meta data, which is used for display reasons on the PowerApp. It has no impact on the SAP landscape itself.
You can check the associated connections on your cloud flows on PowerAutomate when you hit the share button from the navigation ribbon.
Fig.4 Screenshot shared cloud flows
It is always worth to be up to date with the latest governance features and limited access controls as well as to verify your security measures on a regular basis because the cloud evolves quickly. Above setup gives you a reasonably secure configuration. All endpoints are locked down and even the ICF service “/sap/public/ping” does not expose anything sensitive.
Let’s look at the moving parts
The PowerApp consists of four screens (see fig.1), which communicate with Azure through the cloud flows on PowerAutomate.
- A main overview to filter the Azure subscription and list the associated SAP systems.
- A detail view to actually start/stop a SAP system based on its SID chosen on the main screen.
- A list view with the associated VMs of a SID (e.g DB, App server, web dispatcher, client tools VM etc.) based on the Azure tags.
- A calendar-based scheduling view to claim systems in the future for a demo scenario for instance.
- And a help page (accessible through info button in top right corner) to feed issues and feedback into the right channels right away. In our case that is a public GitHub Issue page, but it could be a ServiceNow ticket or similar too.
Ok cool, so how does this map to the cloud flows?
Fig.5 App home screen with mapping to cloud flows in PowerAutomate
For convenience, the Azure subscriptions, list of SIDs and VMs are cached on your mobile device, so you don’t need to pull them each time and hence have a faster mobile experience (on Desktop or Teams you must load each time). This makes especially sense under the assumption, that Subscriptions and SAP systems are likely not going to change daily. If you need an update, just hit the refresh button.
Fig.6 Detail Screen with function mapping to cloud flows
Since we have an automatic stop mechanism to ensure powering off the machines, I added the timer-based flow “NotifySAPLabUserAboutShutdown” to regularly check on the remaining time. Once there are less than 30 mins left, I send push notifications via Teams to the person, who started the VM through the app with the option to extend by one hour if no one else claimed the same system already through the scheduling feature.
The triggered run-book on Azure Automation performs a clean stop and finally deallocates the VM. You could also think about creating a schedule on Azure Automation itself for the start/stop SAP run-book. There are various ways to achieve this. Just make sure you delete the associated sections on the cloud flows to avoid conflict between the approaches.
Fig.7 Screenshot of scheduling screen with cloud flow mapping
Our scheduling screen pulls a custom calendar via the Outlook365 connector. That connector is user-context aware. So, you need to invite all end-users to that calendar for them to see claimed SIDs and create their own claims.
So far so good. That explains the logic flows and interactive UI components. But how does the actual discovery of SAP SIDs based on Goran’s post work?
Automatic SAP SID discovery powered by Azure Tags
Since the start/stop Powershell modules and Azure Automation run-books focus on Azure tags to perform their tasks it was obvious to leverage that approach also for the discovery from the app. The Azure REST API exposes everything that we need to get it done. The bearer access token requires a service principal setup on AAD beforehand. I followed this post to implement it. A quick test with Postman is advisable 😉 There are some managed connectors for Azure ARM too but they were lacking the breakdown that I needed to get the tags and ids in one go. Therefore I did a custom setup with the http connector instead. This might change going forward with connector upgrades.
Fig.9 Screenshot from Cloud Flow “Discover SAP Systems”
Fig.10 call to Azure ARM REST API
We are passing the SAPSystemSID, location, resource group and name to the PowerApp to visualize your SAP infrastructure on Azure
More details on the PowerApp actions and functions
Now, let’s dive into some specific app settings: When the PowerApp loads, it tries to retrieve the Azure Subscriptions from your mobile device cache.
So, when you execute for the first time you will need to hit the refresh button to fill the Collection object and store the values. Caching makes sense because Subscriptions rarely change within your environment and it speeds up the app loading times.
Fig.11 PowerApp refresh button action
ClearCollect ensures, that we flush the collection object, that contains the subscriptions from a previous load. I am splitting the output of the cloud flow by a given placeholder. That makes the JSON handling easier for me. The SaveData function caches the collection on your individual device.
Once you choose a Subscription, the OnChange event will trigger the cloud flow “DiscoverSAPSystems”.
Fig.12 Subscription selection and SAP discover trigger
We are setting a variable CurrentSubs to contain the subscription id (hence we split the combined string by “::” and choose the last part of the array). Secondly, we clear the collection for a fresh set of SAP systems on Subscription changes and feed the list of SIDs with location, resource group, VM name and location to the collection object.
Be aware that a SID could consist of multiple VMs. The Azure Automation Runbooks work with SIDs. That means a start/stop action from one entry (an individual VM respectively) on the PowerApp could impact multiple other VMs!
Now, on to starting a sleeping SAP. See below the function code for the button OnSelect event in the top bar above the design canvas. The internal UpdateContext call allows to keep values and responses from cloud flows during runtime.
Fig.13 PowerApp Studio Start button config
As a first param to the flow “StartSAPBySID” we pass the String “start”, because we re-use the mentioned cloud flow for both the start and stop functionality.
The second parameter uses the function User().Email to pass on the current user. We need that for the Teams push notifications and to store the “Last User” for display on the app for other users to see.
The third parameter is taken from an internal variable that reflects the user’s choice of SAP systems on the home screen. We need it to trigger the Azure Automation Account for the intended SAP System (SID). Again, be aware that the screen shows you an individual VM, but the start/stop action will target a whole SID, which will impact all VMs the SID consists of.
Fourth parameter contains the number for the chosen automatic stop time frame and the last one contains the VM power state. We leverage that to avoid another Azure REST API call, since we obtained the state info when the screen was opened recently.
Furthermore, you can see on the properties on the right (fig.13), that the feedback from the cloud flow can be evaluated to create visual user feedback. In our case we fill the button green if everything went ok or red if bad and grey in all other cases.
The flow starts with a PowerApp trigger (it can only be started through a Power App!).
Fig.14 Overview of simple Start/Stop PowerAutomate flow
The flexible schema on the table storage looks like this and will be created when you start using the cloud flows:
Fig.15 Azure Table Storage view from explorer
Access control to SAP SIDs on the PowerApp
As I mentioned at the beginning, the overall PowerApp access is handled by Azure AD and the PowerPlatform. Access to the Azure resources via the Cloud Flows are tied to the user, who configured the connection in PowerAutomate. To make sure you can separate access to SAP SIDs for each PowerApp user I introduced a call on “Discover SAP Systems” to the Azure REST API checking if the current PowerApp user has any RBAC roles on the VMs of the SID. So, my assumption is, that every person who gets access to start/stop SAP systems gets at least Azure Reader rights on the VM.
Given the result of that call your list of available SIDs changes.
Thoughts on production readiness
- House-keeping and consistent state: The whole approach relies on systematic marking of the Azure VMs using Azure Tags. SAP VMs not tagged are invisible to the PowerApp. So, it is crucial to have good maintenance practice. For our second iteration of this start/stop endeavour we are planning to automate the tagging process. Furthermore, if someone messes with the data on the Table storage you would not see any details anymore on who used it and when it was started but the state and start/stop functionality itself would be unaffected.
- Generalize PowerAutomate flow: Consider adding a nested flow with a http trigger using Azure logicApps, so you can reuse the logic in Fiori/UI5 apps running on SCP or Azure app service for instance. I recommend LogicApps because you can secure the http trigger more fine grained. You would have two cloud flows then. One with the PowerApp trigger, who calls the nested one, containing all the logic via the http trigger, that points at your LogicApp. Be aware that your PowerPlatform Data-Loss-Prevention Policy might prohibit you from having an http trigger with Teams or O365 connectors.
- Govern all SAP SIDs including prod from the PowerApp: Remember one goal was to empower developers to start/stop SAP systems on-demand. To cater for that I added a REST call to show only systems where you have at least reader rights. But how do you protect your prod systems from accidental stop through an admin? Not tagging them, so they don’t show up would be straight forward. Another option could be marking them as prod like in the old days where the productive SAP GUI had a different color than the other systems to make you aware. Either way make a conscious decision about this!
- Distribute the PowerApp efficiently: The mobile app is nice because it is handy for the user and the PowerApp can be put on the home screen like any other mobile app. Publishing the PowerApp on a Teams-Channel might also be interesting depending on your user’s preferences and availability of managed mobile devices. Last option to run from a Browser is straightforward. Furthermore we levarage Microsoft Forms for a self-service sign-up process with approvals via adaptive cards in Teams to an O365 group, that is assigned to the sandbox VMs and the PowerApp.
- More flexible full-stack developer setup: In case you are not happy with the low-code approach and simplifications of PowerPlatform you can easily export your cloud flows as LogicApps from the PowerAutomate UI. To replace the interface you could spin up a UI5 app on an Azure AppService and connect its elements to the LogicApp triggers. Have a look here to get started.
Uhh, that was quite the ride through some low-code development to start/stop and schedule your SAP systems using automation tools and Azure APIs.
Dev or Sandbox systems can and should be powered-off to save resources until they are needed again. But then it is best to offer on-demand self-service capabilities to empower your developers. Waiting for someone to start up a system for you or even filing a ticket creates additional overhead, that can be avoided.
I introduced you to our currently productive PowerApp for our SAP Lab systems at FastTrack, the interactive design to connect the APIs and scripts through our process engine in PowerAutomate as well as explained how to secure this setup.
Self-service sign-up process to Snoozing PowerApp: https://blogs.sap.com/2021/03/08/sap-snoozing-just-sign-me-up-already/
Find the resources, more details on the prerequisites and congfis for this prototype on our GitHub repos.
As always feel free to leave or ask lots of follow-up questions.