-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3d0704e
commit 73e3740
Showing
10 changed files
with
501 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
name: Game Release and Deploy Workflow | ||
|
||
on: | ||
push: | ||
tags: | ||
- '*' | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- run: | | ||
cd scripts | ||
zip -r ../apim-export-release.zip . | ||
- name: Create tag | ||
id: create_tag | ||
shell: bash | ||
run: | | ||
tag=$(basename "${{ github.ref }}") | ||
echo "::set-output name=tag::$tag" | ||
- name: Create Release | ||
id: create_release | ||
uses: actions/create-release@v1 | ||
if: startsWith(github.ref, 'refs/tags/') | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
with: | ||
tag_name: ${{ steps.create_tag.outputs.tag }} | ||
release_name: ${{ steps.create_tag.outputs.tag }} | ||
draft: true | ||
prerelease: false | ||
- name: Release | ||
uses: softprops/action-gh-release@v1 | ||
with: | ||
files: apim-export-release.zip | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"spellchecker.ignoreWordsList": [ | ||
"APIs", | ||
"Dataverse", | ||
"O365" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,111 @@ | ||
# apim-powerplatform-export | ||
# Overview | ||
|
||
This repository expands on [Export APIs from Azure API Management to the Power Platform](https://docs.microsoft.com/en-us/azure/api-management/export-api-power-platform) article, discussing the following use content: | ||
|
||
1. [Why is this important](#why-is-this-important) | ||
|
||
2. [Export of API between different Azure Active Directory Tenants](#export-api-between-different-azure-active-directory-tenants) | ||
|
||
3. [Sample](#sample) Provides sample scripts that can automate the end to end process of automating the deployment of an API from Azure to the Power Platform. | ||
|
||
- [Provisioning Azure Resources](#provisioning-azure-resources) | ||
- [Configure Azure API](#configure-azure-api) | ||
- [Deploy your API to power platform](#deploy-your-api-to-power-platform) | ||
|
||
3. [ALM automation of export process](#alm-automation) | ||
4. [Notes](#notes) | ||
- [O365 User License Context](#o365-licence-context) | ||
- [Fusion Development Teams](#fusion-development-teams) | ||
|
||
## Why Is This Important | ||
|
||
Azure API Management API Export feature makes it easy to take advantage of pro code APIs that you have written in Azure or want to create and expose them to citizen developers so they can leverage them inside their low code Power Platform solutions. | ||
|
||
The published [docs API export document](https://docs.microsoft.com/en-us/azure/api-management/export-api-power-platform) works well when the user manually wants to export the the Azure API Management API to a power platform as a custom connector. This guide looks at automating this process and covering scenarios like when you need to publish to APIs between multiple Azure Active Directory tenants. | ||
|
||
## Export API Between Different Azure Active Directory Tenants | ||
|
||
The article assumes that the Azure subscription and the power platform environment are in the same Azure Active directory tenant. The are various cases where this may not be the case for example: | ||
- You are using your MSDN benefits [https://my.visualstudio.com/benefits](https://my.visualstudio.com/benefits) to use your Azure and Microsoft 365 | ||
Developer subscription (E5) benefits | ||
- You are using your Development or Test Azure subscriptions which are not part of your main organization tenant | ||
- You are deploying to trial subscription https://docs.microsoft.com/en-us/partner-center/advisors-create-a-trial-invitation and a separate pay as you go Azure subscription. | ||
|
||
If scenarios like this apply to you then when you look to publish your API to your Power Apps environment then you will receive an empty list. to work around this gap you can use the [Sample](#sample) section below | ||
|
||
## Sample | ||
|
||
To run this sample download the latest [release](https://github.com/Grant-Archibald-MS/apim-powerplatform-export/releases) from GitHub. Upload the apim-export-release.zip to [https://shell.azure.com](https://shell.azure.com) or Azure Cloud Shell in [https://portal.azure.com](https://portal.azure.com). | ||
|
||
Once uploaded perform thew following steps | ||
|
||
1. unzip the release.zip | ||
|
||
``` | ||
unzip apim-export-release.zip | ||
``` | ||
|
||
2. Change config.json to include your settings replacing TODO values with your settings | ||
|
||
``` | ||
{ | ||
"APIMPublisherEmail": "TODO", | ||
"APIMPublisherName": "TODO2", | ||
"powerPlatformEnvironment": "https://TODO3.crm.dynamics.com", | ||
"powerPlatformTenantId": "TODO4", | ||
"powerPlatformClientId": "TODO5", | ||
"powerPlatformClientSecret": "TODO6", | ||
"tags": [ | ||
"\"Workload name\"=\"Development APIM\"", | ||
"\"Data Classification\"=\"Non-business\"", | ||
"\"Business criticality\"=\"Low\"", | ||
"\"Business Unit\"=\"Unknown\"", | ||
"\"Operations commitment\"=\"Baseline Only\"", | ||
"\"Operations Team\"=\"None\"", | ||
"\"Expected Usage\"=\"Unknown time\"" | ||
] | ||
} | ||
``` | ||
|
||
### Provisioning Azure Resources | ||
|
||
In [https://shell.azure.com](https://shell.azure.com) or Azure Cloud Shell of [https://portal.azure.com](https://portal.azure.com) choosing powershell script environment | ||
|
||
1. ./resources.ps1 | ||
|
||
### Configure Azure API | ||
|
||
TODO: To be updated include Azure Function included | ||
|
||
### Deploy your API to power platform | ||
|
||
#### Azure AD Service Principal | ||
|
||
Ensure that you have created an Azure Active directory with the following | ||
1. API Permissions for Dynamics CRM. | ||
2. Admin granted permissions for Dynamics CRM | ||
3. A secret allocated to the application | ||
|
||
Ensure to that application user has been granted rights (System Customizer) in the power platform environment | ||
|
||
#### Create Connector | ||
|
||
In [https://shell.azure.com](https://shell.azure.com) or Azure Cloud Shell of [https://portal.azure.com](https://portal.azure.com) choosing powershell script environment | ||
|
||
1. ./export-apim.ps1 | ||
|
||
## ALM Automation | ||
|
||
You can use the sample scripts above to include them in your build process | ||
|
||
## Notes | ||
|
||
### O356 License Context | ||
|
||
As at April 2021 as covered in [Licensing overview for Microsoft Power Platform](https://docs.microsoft.com/en-us/power-platform/admin/pricing-billing-skus) Power Apps include limited use rights included with Office 365 licenses to Export Azure API Management APIs to the Power platform. | ||
|
||
This feature enable Customers to publish their Azure backend service as APIs and export these APIs to the Power Platform as custom connectors via Azure API Management. Customers with eligible Office 365 licenses that include Dataverse for Teams can use these connectors for custom applications, flows, and chatbots running in Teams and to connect Azure backend services. [Source](https://download.microsoft.com/download/9/5/6/9568EFD0-403D-4AE4-95F0-7FACA2CCB2E4/Power%20Apps,%20Power%20Automate%20and%20Power%20Virtual%20Agents%20Licensing%20Guide%20-%20Apr%202021.pdf). Appendix B in this guide includes specific O365 licenses that are eligible for this for this feature. | ||
|
||
### Fusion Development Teams | ||
|
||
You can use this feature as a first step to help integrate the concept of building fusion development teams including business, development and IT teams to build a solution. Using this base you can then expand into other premium connectors to accelerate and nurture fusion team development to build and deliver solutions in our organization. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"APIMPublisherEmail": "[email protected]", | ||
"APIMPublisherName": "Grant Archibald", | ||
"powerPlatformEnvironment": "https://orgd1648131.crm.dynamics.com", | ||
"powerPlatformTenantId": "8a235459-3d2c-415d-8c1e-e2fe133509ad", | ||
"powerPlatformClientId": "6bca951c-ffc7-4345-b438-daa6a0326c18", | ||
"powerPlatformClientSecret": "xKRexG5_d4Kj_ReD5WcN85dtj~3amU4~1A", | ||
"tags": [ | ||
"\"Workload name\"=\"Development APIM\"", | ||
"\"Data Classification\"=\"Non-business\"", | ||
"\"Business criticality\"=\"Low\"", | ||
"\"Business Unit\"=\"Unknown\"", | ||
"\"Operations commitment\"=\"Baseline Only\"", | ||
"\"Operations Team\"=\"None\"", | ||
"\"Expected Usage\"=\"Unknown time\"" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
<# | ||
.NOTES | ||
============================================================================================== | ||
Copyright(c) Microsoft Corporation. All rights reserved. | ||
File: apim.ps1 | ||
Purpose: Configure and deploy azure APIM Management | ||
Version: 0.1.0 | ||
============================================================================================== | ||
.SYNOPSIS | ||
Define and provision APIM Management | ||
.DESCRIPTION | ||
Sample script to provision Azure Azure API Management | ||
#> | ||
|
||
class APIM { | ||
[string] Create($resources, $config) { | ||
$apimMatch = $resources.Where({ $_.type -eq "Microsoft.ApiManagement/service"}) | ||
|
||
$apiName = "" | ||
Switch ($apimMatch.Count) { | ||
0 { | ||
$name = (New-Guid).Guid.Replace("-", "").Substring(0, 23) | ||
$apiName = "A${name}" | ||
Write-Host "Creating API Management" | ||
az apim create --name $apiName --publisher-email $config.APIMPublisherEmail --publisher-name $config.APIMPublisherName --sku-name $config.apiSku --resource-group $config.resourceGroup | ||
} | ||
1 { | ||
$apiName = $apimMatch[0].name | ||
} | ||
} | ||
|
||
return $apiName | ||
} | ||
|
||
[string] ExportSwagger($config) { | ||
Write-Host "Searching for APIM" | ||
|
||
$apim = (az apim list -g $config.resourceGroup | ConvertFrom-Json) | ||
|
||
if ( $apim.count -eq 1 ) { | ||
Write-Host "Found APIM" | ||
$serviceName = $apim[0].name | ||
|
||
Write-Host "Searching for API" | ||
$apis = (az apim api list --resource-group Azure-APIM-Management-Test --service-name $serviceName | ConvertFrom-Json) | ||
|
||
$match = $apis | Where-Object { $_.name -eq $config.apiToExport } | ||
|
||
if ($match.length -eq 1) { | ||
Write-Host "Found api" | ||
|
||
$token = (az account get-access-token --resource="https://management.azure.com" --query accessToken --output tsv) | ||
$headers = @{ | ||
"Authorization" = "Bearer $token" | ||
"Content-Type" = "application/json" | ||
} | ||
|
||
$apiId = $match[0].id | ||
$url = [Uri]"https://management.azure.com${apiId}?format=swagger-link&export=true&api-version=2021-01-01-preview" | ||
|
||
$apiDefinition = (Invoke-RestMethod -Method GET -Uri $url -Header $headers) | ||
$downloadUrl = [Uri]$apiDefinition.value.link | ||
|
||
$swagger = (Invoke-WebRequest -Uri $downloadUrl -Method GET) | ||
|
||
return $swagger | ||
|
||
} | ||
} else { | ||
$apiCount = $apim.count | ||
Write-Host "Found $apiCount APIM instances, searhing for single" | ||
} | ||
return "" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
<# | ||
.NOTES | ||
============================================================================================== | ||
Copyright(c) Microsoft Corporation. All rights reserved. | ||
File: powerplaform.ps1 | ||
Purpose: Configure and deploy Power Platform resources | ||
Version: 0.1.0 | ||
============================================================================================== | ||
.SYNOPSIS | ||
Configure and deploy Power Platform resources | ||
.DESCRIPTION | ||
Sample script to provision Power Platform connectors | ||
#> | ||
|
||
class PowerPlatform { | ||
[string] Login($config) { | ||
$resourceName = $config.powerPlatformEnvironment | ||
$tenantId = $config.powerPlatformTenantId | ||
$clientId = $config.powerPlatformClientId | ||
$clientSecret = $config.powerPlatformClientSecret | ||
|
||
$body = @{grant_type="client_credentials";resource=$resourceName;client_id=$ClientID;client_secret=$clientSecret} | ||
|
||
$loginURL = 'https://login.windows.net' | ||
|
||
$url = [Uri]"$loginURL/$tenantId/oauth2/token?api-version=1.0" | ||
|
||
return (Invoke-RestMethod -Method Post -Uri $url -Body $body).access_token | ||
} | ||
|
||
ImportConnector($config, [string] $accessToken, [string]$swagger) { | ||
$headers = @{ | ||
"Authorization" = "Bearer $accessToken" | ||
"OData-Version" = "4.0" | ||
"Content-Type" = "application/json" | ||
} | ||
|
||
# https://docs.microsoft.com/en-us/dynamics365/customer-engagement/web-api/connector?view=dynamics-ce-odata-9 | ||
|
||
$swaggerData = ($swagger | ConvertFrom-Json) | ||
|
||
$displayName = $swaggerData.info.title -replace " ", "" | ||
|
||
#TODO - Add to a solution | ||
$name = "new_5F" + $displayName.ToLower() | ||
|
||
$body = @{ | ||
"name" = $name | ||
"displayname" = $displayName | ||
"connectortype" = 1 | ||
"openapidefinition" = $swagger | ||
} | ||
|
||
$json = ($body | ConvertTo-Json) | ||
|
||
$Failure = $NULL | ||
|
||
$url = $config.powerPlatformEnvironment | ||
if ( !$url.endsWith("/") ) { | ||
$url += "/" | ||
} | ||
$url += "api/data/v9.0/connectors" | ||
|
||
$url = [Uri]$url | ||
|
||
$resp = try { Invoke-WebRequest -Method POST -Uri $url -Headers $headers -Body $json } catch { $Failure = $_.Exception.Response } | ||
|
||
Write-Host $resp | ||
Write-Host $Failure | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"APIMPublisherEmail": "TODO", | ||
"APIMPublisherName": "TODO2", | ||
"powerPlatformEnvironment": "https://TODO3.crm.dynamics.com", | ||
"powerPlatformTenantId": "TODO4", | ||
"powerPlatformClientId": "TODO5", | ||
"powerPlatformClientSecret": "TODO6", | ||
"tags": [ | ||
"\"Workload name\"=\"Development APIM\"", | ||
"\"Data Classification\"=\"Non-business\"", | ||
"\"Business criticality\"=\"Low\"", | ||
"\"Business Unit\"=\"Unknown\"", | ||
"\"Operations commitment\"=\"Baseline Only\"", | ||
"\"Operations Team\"=\"None\"", | ||
"\"Expected Usage\"=\"Unknown time\"" | ||
] | ||
} |
Oops, something went wrong.