Code Monkey home page Code Monkey logo

apimanagementarmtemplatecreator's Introduction

API Management ARM Template Creator

This is a PowerShell script module to extract API Management to ARM templates, focus is to provide a module for easy deployments.

How to use

Install from PowerShell Gallery
PS> Install-Module -Name APIManagementTemplate

Update to latest version from PowerShell Gallery
PS> Update-Module -Name APIManagementTemplate

Install-Module is part of PowerShellGet which is included on Windows 10 and Windows Server 2016. See this link for installation instructions on older platforms.

Import without installing
Clone the project, open, and build.

Open PowerShell and Import the module:

Import-Module C:\{pathToSolution}\APIManagementARMTemplateCreator\APIManagementTemplate\bin\Debug\APIManagementTemplate.dll

Run the PowerShell command Get-APIManagementTemplate. You can pipe the output as needed, and recommended you pipe in a token from armclient

armclient token 80d4fe69-xxxx-4dd2-a938-9250f1c8ab03 | Get-APIManagementTemplate -APIManagement MyApiManagementInstance -ResourceGroup myResourceGroup -SubscriptionId 80d4fe69-xxxx-4dd2-a938-9250f1c8ab03 | Out-File C:\template.json

Example when user is connected to multitenants:

Get-APIManagementTemplate -APIManagement MyApiManagementInstance -ResourceGroup myResourceGroup -SubscriptionId 80d4fe69-xxxx-4dd2-a938-9250f1c8ab03 -TenantName contoso.onmicrosoft.com

Specifications

Parameter Description Required Default
APIManagement Name of the API Management instance true
ResourceGroup The name of the Resource Group true
SubscriptionId The Subscription id (guid) true
TenantName Name of the Tenant i.e. contoso.onmicrosoft.com false
APIFilters Filter for what API's to exort i.e: path eq 'api/v1/currencyconverter' or endswith(path,'currencyconverter'). In addition to this, is it also possible to filter on productname i.e.: productname eq 'product-x') false
ExportAuthorizationServers Flag indicating if Authorization servers should be exported false true
ExportPIManagementInstance Flag indicating if the API Management instance should be exported false true
ExportGroups Flag indicating if Groups should be exported false true
ExportProducts Flag indicating if Products should be exported false true
ExportTags Flag indicating if Tags should be exported false
ExportSwaggerDefinition Export the API operations and schemas as a swagger/Open API 2.0 definition. If set to false then the operations and schemas of the API will be included as arm templates false false
Token An AAD Token to access the resources - should not include Bearer, only the token false
ParametrizePropertiesOnly If parameters only should be created for properties such as names of apim services or logic apps and not names of groups, apis or products false false
ReplaceSetBackendServiceBaseUrlWithProperty If the base-url of with should be replaced with a property instead of a parameter. If this is false you will not be able to set SeparatePolicyFile=true for Write-APIManagementTemplates when you have set-backend-service with base-url-attribute in a policy false false
FixedServiceNameParameter True if the parameter for the name of the service should have a fixed name (apimServiceName). Otherwise the parameter name will depend on the name of the service (service_PreDemoTest_name) false false
CreateApplicationInsightsInstance If an Application Insights instance should be created when used by a logger. Otherwise you need to provide the instrumentation key of an existing Application Insights instance as a parameter false false
DebugOutPutFolder If set, result from rest interface will be saved to this folder false
ApiVersion If set, api result will be filtered based on this value i.e: v2 false
ClaimsDump A dump of claims piped in from armclient - should not be manually set false
ParameterizeBackendFunctionKey Set to 'true' if you want the backend function key to be parameterized false false
SeparatePolicyOutputFolder Set to an output folder if you want to save the policies in a separate file. The output folder must be relative to the directory _artifactsLocation/_artifactsBlobPrefix. Parameters _artifactsLocation, _artifactsBlobPrefix and _artifactsSASToken are added to the template automatically. This parameter is useful when the policy size exceeds the 16KB limit and you do not want separate ARM templates for all objects. false
ChainDependencies Set to 'true' if you get the error "Operation on the API is in progress". This option chains the product apis in order to reduce parallelism false false

After extraction a parameters file can be created off the ARMTemplate.

Multiple small ARM-templates with Write-APIManagementTemplates

Use Write-APIManagementTemplates generate many small ARM templates (as suggested in https://github.com/Azure/azure-api-management-devops-example) instead of one big ARM template.

armclient token 80d4fe69-xxxx-4dd2-a938-9250f1c8ab03 | Get-APIManagementTemplate -APIManagement MyApiManagementInstance -ResourceGroup myResourceGroup -SubscriptionId 80d4fe69-xxxx-4dd2-a938-9250f1c8ab03 | Write-APIManagementTemplates -OutputDirectory C:\temp\templates -SeparatePolicyFile $true

Specifications

Parameter Description Required Default
ApiStandalone If the APIs should be able to be deployed independently of the rest of the resources false true
ListApiInProduct If true only the names of the API will be added as array parameter false false
OutputDirectory The directory where the templates are written to false .
SeparatePolicyFile If the policies should be written to a separate xml file. If set to false then the policies are included as a part of the arm templates false false
SeparateSwaggerFile Swagger/Openapi definitions are written to a separate file. If set to false then the Swagger/Openapi definitions are included as part of the arm templates false false
MergeTemplates If the template already exists in the output directory, it will be merged with the new result. false false
GenerateParameterFiles If parameter files should be generated false false
ReplaceListSecretsWithParameter If the key to an Azure Function should be defined in a parameter instead of calling listsecrets false false
AlwaysAddPropertiesAndBackend Always add properties and backend, usefull when having logicapp backends and this service is not generated false false

| DebugTemplateFile | If set, the input ARM template is written to this file | false | | | ARMTemplate | The ARM template piped from Get-APIManagementTemplate - should not be manually set | false | |

Using OpenAPI/Swagger definition files

It is possible to generate ARM templates that use Openapi/Swagger 2.0 definition files to describe the operations and schemas of your APIs.

The advantage is that when there is a change in the backend API you just need to update the OpenAPI/Swagger definition file of your API. No need to modify the ARM templates of the operations and schemas by hand or to change the source API Management instance and then update the ARM templates with this tool.

Use ExportSwaggerDefinition=$true as parameter to Get-APIManagementTemplate and SeparateSwaggerFile=$true as parameter to Write-APIManagementTemplates.

Due to limitations in Azure it is not supported to use ExportSwaggerDefinition=$true without using SeparateSwaggerFile=$true.

armclient token 80d4fe69-xxxx-4dd2-a938-9250f1c8ab03 | Get-APIManagementTemplate -APIManagement MyApiManagementInstance -ResourceGroup myResourceGroup -SubscriptionId 80d4fe69-xxxx-4dd2-a938-9250f1c8ab03 -ParametrizePropertiesOnly $true -FixedServiceNameParameter $true -CreateApplicationInsightsInstance $true -ReplaceSetBackendServiceBaseUrlWithProperty $true -ExportSwaggerDefinition $true | Write-APIManagementTemplates -OutputDirectory C:\temp\templates -ApiStandalone $true -SeparatePolicyFile $true -SeparateSwaggerFile $true -MergeTemplates $true -GenerateParameterFiles $true -ReplaceListSecretsWithParameter $true -ListApiInProduct $false

If you have a host property in your OpenAPI/Swagger definition it will override the serviceUrl property of your API. So if you want to have different serviceUrls for different environments (for example test and production environments) you need to do one of the following two options

  • Write a policy that changes the backend url
  • Modify the OpenAPI/Swagger definition file so that it contains the correct url in host, basePath and schemes before you deploy it

apimanagementarmtemplatecreator's People

Contributors

chrismansfield avatar danbyrne avatar dependabot[bot] avatar geronius avatar joeyeng avatar lfalck avatar massimoc avatar mlogdberg avatar mmvb avatar nilshedstrom avatar pgussow avatar twinpiloot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

apimanagementarmtemplatecreator's Issues

Get-APIManagementTemplate stopped working for Consumption instances

Hi,

Running with the following parameters:

Get-APIManagementTemplate
-APIFilters "name eq '$apiName'" -Token $account.accessToken
-APIManagement $apimServiceName -ResourceGroup $resourceGroup
-SubscriptionId $subscription -ExportGroups $false
-ParametrizePropertiesOnly $true -FixedServiceNameParameter $true
-DebugOutPutFolder 'debug'`

Failes with error:
Get-APIManagementTemplate Aggregation Exception thrown, One or more errors occurred. (Object reference not set to an instance of an object.), first Exception message is: Object reference not set to an instance of an object., for more information read the output file.

The debug folder contains the following files:

  • service-xxx.json
  • service-xxx-policies.json
  • service-xxx-identityProviders.json

service-xxx-identityProviders.json contains the following:
{"error":{"code":"MethodNotAllowedInPricingTier","message":"Method not allowed in Consumption pricing tier","details":null}}

I've added another APIM instance to the same resource group running Developer sku, and it works as expected.

backend-id Policy substitution

Hi, your tool is very interesting.
I tried to use it for my client project but I have found an issue or at least an interrogation.

How can we switch the backend-id in an operation policy when we have different environment ?

For the test I have done, the backend ID is stored in hard in the xml policy file.
Can we do a find and replace on the xml files and when is it best practice to make it ?

I also tried to use a Named Value variable in the policy. It works very well in azure apim but the arm creator tool fails with this error when there is a named value as backendid:


Write-APIManagementTemplates : Unexpected character encountered while parsing value: A. Path '', line 0, position 0.
Au caractère Ligne:1 : 346
+ ... ion $true | Write-APIManagementTemplates -OutputDirectory C:\temp\tem ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-APIManagementTemplates], JsonReaderException
    + FullyQualifiedErrorId : Newtonsoft.Json.JsonReaderException,APIManagementTemplate.WriteApiManagementTemplatesCmdlet

Support for new function app import functionality

The the new APIM import functionality for function apps no longer uses rewrite-uri policies to set the function key querystring. The function key is now stored in a backends resource:

{
      "comments": "Generated for resource /subscriptions/ABC/resourceGroups/apimanagement-dev-resourcegroup/providers/Microsoft.ApiManagement/service/apim/backends/function",
      "type": "Microsoft.ApiManagement/service/backends",
      "name": "[concat(parameters('service_apim_name'), '/' ,'function')]",
      "apiVersion": "2017-03-01",
      "properties": {
        "title": null,
        "description": "[parameters('function_siteName')]",
        "url": "[concat('https://',toLower(parameters('function_siteName')),'.azurewebsites.net/')]",
        "protocol": "http",
        "resourceId": "[concat('https://management.azure.com/','subscriptions/',subscription().subscriptionId,'/resourceGroups/',parameters('function_resourceGroup'),'/providers/Microsoft.Web/sites/',parameters('function_siteName'))]",
        "credentials": {
          "query": {
            "code": [
              "{{function-key}}"
            ]
          }
        }
      },
      "resources": [],
      "dependsOn": []
    }

The tool needs to add a property for the {{function-key}} referenced by the backend.

References to version sets shouldn't have hardcoded subscription id's

Right now we're getting failures when deploying to instances of APIM in other subscriptions.

We should be able to replace this:

"apiVersionSetId": "/subscriptions/HARDCODED_SUBSCRIPTION_ID/resourceGroups/RESOURCEGROUP_NAME/providers/Microsoft.ApiManagement/service/APIM_NAME/api-version-sets/kjdhf2h3khklkj324kjkl3"

with this:

"apiVersionSetId": "[resourceId('Microsoft.ApiManagement/service/api-version-sets', parameters('service_apim_name'), 'kjdhf2h3khklkj324kjkl3')]"

Exception message is: Value cannot be null. Parameter name: input

When I run the following script:

armclient login
armclient token | Get-APIManagementTemplate -APIManagement myInstanceName -ResourceGroup myResourceGroup -SubscriptionId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -DebugOutPutFolder C:\Users\Me\Downloads | Out-File C:\Users\Me\Downloads\output-template.json

I get an error:

Get-APIManagementTemplate : Aggregation Exception thrown, One or more errors occurred., first Exception message is: Value cannot be null.
Parameter name: input, for more information read the output file.
At line:3 char:19
+ ... ent token | Get-APIManagementTemplate -APIManagement qa-opti-apim-por ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Get-APIManagementTemplate], Exception
    + FullyQualifiedErrorId : System.Exception,APIManagementTemplate.GeneratorCmdlet

I don't believe there's a parameter called input. Am I using this tool incorrectly?

Getting FileNotFoundException

Get-APIManagementTemplate : Could not load file or assembly 'System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. The system cannot find the file specified.
At line:1 char:1

  • Get-APIManagementTemplate -APIManagement maerskintermodal -ResourceGr ...
  • CategoryInfo : NotSpecified: (:) [Get-APIManagementTemplate], FileNotFoundException
  • FullyQualifiedErrorId : System.IO.FileNotFoundException,APIManagementTemplate.GeneratorCmdlet

Policy files not extracted anymore

With Commit f3e948b my policy file are not extracted correctly anymore.

Is see this change
var policyPropertyName = policy["properties"].Value<string>("policyContent") == null ? "value" : "policyContent"; in the file TemplateGenerator.cs but not in TemplatesGenerator.cs. Then I add the same line of code there the xml policy files are filled again they still are not parsed rigth. I see this in my api-$$$template.json file. The value is also left behind. Can you fix this please?

"type": "Microsoft.ApiManagement/service/apis/operations/policies",
              "name": "[concat(parameters('apimServiceName'), '/', 'KPNEAIExport', '/', '5daa10ccab38db091f026130', '/', 'policy')]",
              "apiVersion": "2018-01-01",
              "properties": {
                "value": "<!--\r\n    IMPORTANT:\r\n    - Policy elements can appear only within the <inbound>, <outbound>, <backend> section elements.\r\n    - To apply a policy to the incoming request (before it is forwarded to the backend service), place a corresponding policy element within the <inbound> section element.\r\n    - To apply a policy to the outgoing response (before it is sent back to the caller), place a corresponding policy element within the <outbound> section element.\r\n    - To add a policy, place the cursor at the desired insertion point and select a policy from the sidebar.\r\n    - To remove a policy, delete the corresponding policy statement from the policy document.\r\n    - Position the <base> element within a section element to inherit all policies from the corresponding section element in the enclosing scope.\r\n    - Remove the <base> element to prevent inheriting policies from the corresponding section element in the enclosing scope.\r\n    - Policies are applied in the order of their appearance, from the top down.\r\n    - Comments within policy elements are not supported and may disappear. Place your comments between policy elements or at a higher level scope.\r\n-->\r\n<policies>\r\n  <inbound>\r\n    <base />\r\n  </inbound>\r\n  <backend>\r\n    <base />\r\n  </backend>\r\n  <outbound>\r\n    <base />\r\n  </outbound>\r\n  <on-error>\r\n    <base />\r\n  </on-error>\r\n</policies>",
                "format": "xml",
                "contentFormat": "xml-link",
                "policyContent": "[concat(parameters('repoBaseUrl'), '/api-KPNEAIExport/api-KPNEAIExport.5daa10ccab38db091f026130.policy.xml', parameters('_artifactsLocationSasToken'))]"
              },

Parameter ExportAuthroizationServers has no effect

In the list of parameters in README.md you can find

  • ExportAuthroizationServers
  • Flag inidicating if Authroization servers should be exported, default true

But when looking at the code you find that this parameter is not used. The code DeploymentTemplate.ParameterizeAuthorizationServers is never called and the test ParameterizeAuthorizationServers is commented.

I think that we have two options

  1. The flag parameter should effect how the template is generated (implement support for Authorization Servers)
  2. Remove the parameter and the code that is not used to avoid confusion for the users and developers.

Extracting and Deploying API Revisions

When extracting an API with revisions, I see only resource metadata for the latest revision in the template file created. As all of the API resources are revision specific, I would expect to see resource definitions for both of my API revisions. Related to this, I can't seem to deploy my revision to a different resource group with the template created. There is an error that the operation already exists, even though it is deploying revision 2. Are API revisions generally not supported for ARM? I have searched extensively, but am unable to find any documentation that pertains to this use case.

Error in Write-APIManagementTemplates

I've been using this for months but its been a week that Write-APIManagementTemplates is giving me this error. I thought that it was just intermittent at first but no. Please help

image

The 'Get-APIManagementTemplate' command was found in the module, but the module could not be loaded

The latest version 1.4.200 of APIManagementTemplate results in an error when imported in Powershell 5.

Information:

PS C:\WINDOWS\system32> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.22621.1778
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.22621.1778
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

PS C:\WINDOWS\system32> Get-InstalledModule -Name APIManagementTemplate

Version              Name                                Repository           Description
-------              ----                                ----------           -----------
1.4.200              APIManagementTemplate               PSGallery            Extract Azure API Management to ARM templates

PS C:\WINDOWS\system32> Import-Module -Name APIManagementTemplate -Debug
VERBOSE: Loading module from path 'C:\Program
Files\WindowsPowerShell\Modules\APIManagementTemplate\1.4.200\APIManagementTemplate.psd1'.

Confirm
Continue with this operation?
[Y] Yes  [A] Yes to All  [H] Halt Command  [S] Suspend  [?] Help (default is "Y"): A
VERBOSE: Cannot verify the Microsoft .NET Framework version 4.5.2 because it is not included in the list of permitted
versions.
VERBOSE: Populating RepositorySourceLocation property for module APIManagementTemplate.
VERBOSE: Loading module from path 'C:\Program
Files\WindowsPowerShell\Modules\APIManagementTemplate\1.4.200\APIManagementTemplate.dll'.
Import-Module : Could not load file or assembly 'Newtonsoft.Json, Version=12.0.0.0, Culture=neutral,
PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies. The system cannot find the file specified.
At line:1 char:1
+ Import-Module -Name APIManagementTemplate -Debug
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Import-Module], FileNotFoundException
    + FullyQualifiedErrorId : System.IO.FileNotFoundException,Microsoft.PowerShell.Commands.ImportModuleCommand

If I downgrade to the previous version, it works again in powershell 5 (see below):

PS C:\WINDOWS\system32> Install-Module -Name APIManagementTemplate -RequiredVersion 1.4.197
PS C:\WINDOWS\system32> Get-InstalledModule -Name APIManagementTemplate -AllVersions

Version              Name                                Repository           Description
-------              ----                                ----------           -----------
1.4.197              APIManagementTemplate               PSGallery            Extract Azure API Management to ARM te...


PS C:\WINDOWS\system32> Import-Module -Name APIManagementTemplate -Debug
VERBOSE: Loading module from path 'C:\Program
Files\WindowsPowerShell\Modules\APIManagementTemplate\1.4.197\APIManagementTemplate.psd1'.

Confirm
Continue with this operation?
[Y] Yes  [A] Yes to All  [H] Halt Command  [S] Suspend  [?] Help (default is "Y"): A
VERBOSE: Cannot verify the Microsoft .NET Framework version 4.5.2 because it is not included in the list of permitted
versions.
VERBOSE: Populating RepositorySourceLocation property for module APIManagementTemplate.
VERBOSE: Loading module from path 'C:\Program
Files\WindowsPowerShell\Modules\APIManagementTemplate\1.4.197\APIManagementTemplate.dll'.
VERBOSE: Exporting cmdlet 'Get-ParameterTemplate'.
VERBOSE: Exporting cmdlet 'Write-APIManagementTemplates'.
VERBOSE: Exporting cmdlet 'Get-APIManagementTemplate'.
VERBOSE: Importing cmdlet 'Get-APIManagementTemplate'.
VERBOSE: Importing cmdlet 'Get-ParameterTemplate'.
VERBOSE: Importing cmdlet 'Write-APIManagementTemplates'.

I did not run into this issue with the latest version of APIManagementTemplate module (1.4.200) in Powershell Core.
If more information is needed, please let me know.

Object reference not found issue

Aggregation exception thrown, se following exceptions for more information
Exception: Object reference not set to an instance of an object.
at APIManagementTemplate.TemplateGenerator.d__11.MoveNext() in C:\Users\Admin\Source\Repos\APIManagementARMTemplateCreator2\APIManagementTemplate\TemplateGenerator.cs:line 141

I have fixed this issue in my branch https://github.com/brainplant/APIManagementARMTemplateCreator .See if it can merged to master.

API Product not getting the proper dependson

When exporting with products, the product is missing dependson for the API and that makes the first deployment fail but if the deployment is executed again eventually it will work since the api will be there.

Support for backend arm template

When using the "Azure API Management DevOps Resource Kit", we get arm templates for all backends that are registered inside our APIM.

When using your module, we only get the policy files, with a reference to the backend.

Did I miss something or doesn't your module support backends exported into ARM templates?

DeploymentTemplate.cs:line 205 - Object reference not set to an instance of an object

DeploymentTemplate.cs:line 205 - Object reference not set to an instance of an object


  • Commit: ea0cd95

  • Command: Get-APIManagementTemplate -APIManagement APIResourceName -ResourceGroup ResourceGroup -SubscriptionId SubId

  • Error:
    Aggregation exception thrown,
    Exception: Object reference not set to an instance of an object.
    at APIManagementTemplate.Models.DeploymentTemplate.AddAPIManagementInstance(JObject restObject) in C:_Src\Sdbx\APIManagementARMTemplateCreator\APIManagementTemplate\Models\DeploymentTemplate.cs:line 205
    at APIManagementTemplate.TemplateGenerator.d__11.MoveNext() in C:_Src\Sdbx\APIManagementARMTemplateCreator\APIManagementTemplate\TemplateGenerator.cs:line 58

Object reference not set to an instance of an object

Aggregation exception thrown, se following exceptions for more information
Exception: Object reference not set to an instance of an object.
at APIManagementTemplate.Models.DeploymentTemplate.AddAPIManagementInstance(JObject restObject)
at APIManagementTemplate.TemplateGenerator.d__26.MoveNext()

Issue with extra / in linked template URL in Azure DevOPS

Hi,
Maybe I missed something when using the Get-APIMTemplate cmdline but now that I have all my ARMs templates, I have an error due to a / in the templateLink.

I have an Azure DevOPS pipeline with 2 tasks:

  • An Azure File Copy to an Azure Blob storage. At the end of this task I retrieve the SAS token and the location of the storage thanks to output variables of the tasks
  • Then I overwrite the repoBaseUrl parameter of the master template with the output of the task in a Azure RM Deployment task.

Unfortunately the output of the Azure File Copy task contains a "/" at the end of the path and in the template there is a concatenation of the repoUrl I have overwritten with the path of the linked template. So the linked template cannot be found...

Am i missing something?

Listsecret for function key wrong operation name?

Hi @MLogdberg,

So you know when you import a function app as an api it will generate some code for the operation name (e.g. 5b16e9ec2c99226c5c42d98e)? The tool is using these codes for the operation name in the listsecret function call. Shouldn't it be the actual function app operation name, not these APIM codes that the function app doesn't know anything about?

Example:
[listsecrets(resourceId(parameters('FunctionApp_funcappname_resourceGroup'),'Microsoft.Web/sites/functions', parameters('FunctionApp_funcappname_siteName'), '5b16e9ec2c99226c5c42d98e'),'2015-08-01').key]

WriteError when long ApiVersionSetName

I use quite long names for my versionsetname. This results in write errors in de templategenerator. Is is possible to fix the versionsetname link the servicename?

Get-APIManagementTemplate could not load propertly

When executing Get-APIManagementTemplate I get
Could not load type 'System.Security.Cryptography.SHA256Cng' from assembly 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'

I load the modules like this:
foreach($requiredModule in @("APIManagementTemplate","Az") ){
if(! $(Get-InstalledModule $requiredModule)){
Write-host "Loading $requiredModule ..."
Install-Module -Name $requiredModule -AllowClobber -Force -Scope CurrentUser -Repository PSGallery
}
Update-Module -Name $requiredModule
Write-host "Loaded $requiredModule"
}

The resource IfsGatewayFunctionApp is not defined in the template

After the last update, my templates do not deploy with the following error:

The resource 'Microsoft.ApiManagement/service/myapim instance/apis/IfsGatewayFunctionApp/operations/5b695641f4c1942a581f51e6' is not defined in the template.

Seems that there is a dependency on an API that I do not have.

Securestring should be null by default

When exporting today the actual value from Named values are set as the defaultvalue of the property. This is not good by obvious reasons.

Would prefer if this instead was set to null in the export.

For example

 "Alerts-ResourceKey_value": {
      "type": "securestring",
      "defaultValue": "0VNs80QFoZuI4BEomZ1UnumLeYmUCGCXXXXXXXXX="
    },

property_xxxxx_name

In the ARM template there is a depends_on, which is:
"[resourceId('Microsoft.ApiManagement/service/properties', parameters('service_TALAPIDev_name'),parameters('property_58db35e8e3f12111f4362527_name'))]",

However I cannot find any reference to this in the ARM template, and the template still seems to work if I remove this as a dependency...
Is this expected? Or has something changed, and there is supposed to be some API-based property (supposed to be a property for the name of the API?)

It looks to come from this code snipped:
if (!parametrizePropertiesOnly)
{

                    foreach (var apiName in identifiedProperty.apis)
                    {
                        var apiTemplate = template.resources.Where(rr => rr.Value<string>("name") == apiName).FirstOrDefault();
                        apiTemplate.Value<JArray>("dependsOn").Add($"[resourceId('Microsoft.ApiManagement/service/properties', parameters('service_{servicename}_name'),parameters('property_{propertyObject.Value<string>("name")}_name'))]");
                    }
                }

But I havent spent the time to figure out what this is supposed to be doing, so I thought I'd reach out instead...

I've uploaded the sample ARM template for your review
TALAPIDev_increment - Copy.zip
Thanks

PessimisticConcurrencyConflict: Operation on the API is in progress

When you create a template with multiple APIs and Products, you might get the following error when you deploy the template:

{
"code": "Conflict",
"message": "{\r\n "error": {\r\n "code": "PessimisticConcurrencyConflict",\r\n "message": "Operation on the API is in progress",\r\n "details": null\r\n }\r\n}"
}

Extracting API Manager with swagger files

I'm trying to use your tool to extract an API Manger to an ARM template with OpenAPI and swagger templates. Currently what the tool has given me so far is not deployable. I was hoping you could help me out. First I ran into issues just getting the extraction to work.

In your code TemplateGenerator.cs line 261 the code reads:

                           var swaggerUrl = swaggerExport.Value<string>("link");
                            var swaggerContent = await resourceCollector.GetResourceByURL(swaggerUrl);
                            var serviceUrl = apiInstance["properties"].Value<string>("serviceUrl");
                            if (!string.IsNullOrWhiteSpace(serviceUrl))
                            {
                                var serviceUri = new Uri(serviceUrl);
                                swaggerContent["host"] = serviceUri.Host;
                                swaggerContent["basePath"] = serviceUri.AbsolutePath;
                                swaggerContent["schemes"] = JArray.FromObject(new[] {serviceUri.Scheme});
                            }

                            apiTemplateResource["properties"]["contentValue"] = swaggerContent.ToString();

problem is swaggerUrl is always null and the code would throw an exception a little later.

I modified it it to this, and I am not sure if this was the right thing to do or not, but I did get swagger files:

                        var swaggerUrl = swaggerExport.Value<string>("link") ??
                                         swaggerExport["value"].Value<string>("link");
                        if (!string.IsNullOrWhiteSpace(swaggerUrl))
                        {
                            var swaggerContent = await resourceCollector.GetResourceByURL(swaggerUrl);
                            var serviceUrl = apiInstance["properties"].Value<string>("serviceUrl");
                            if (!string.IsNullOrWhiteSpace(serviceUrl))
                            {
                                var serviceUri = new Uri(serviceUrl);
                                swaggerContent["host"] = serviceUri.Host;
                                swaggerContent["basePath"] = serviceUri.AbsolutePath;
                                swaggerContent["schemes"] = JArray.FromObject(new[] {serviceUri.Scheme});
                            }

                            apiTemplateResource["properties"]["contentValue"] = swaggerContent.ToString();
                        }

My next issue is that the deployment for the standard echo api seemed to be off. master.template.json seemed to referencing the swagger template.json file, but that deployment wasn't defined in that file. Also my other api doesn't seem to have a deployment defined either. Do you have any thoughts or ideas on these issues?

Thanks,
Aaron

API's with Client Certificates: Template generation and deployment

Hi Mattias,

First of all thx for this tool.

Situation:

  • I have in APIM 4 Api's:
    • 2 API's are SOAP service and both backends are protected with Client Certificates (Coupled to Certificate)
    • 2 API's are regular Rest

I generated successfully APIM ARM template via the creator (APIManagementARMTemplate latest commit bc5ccd6).
(Parameter file also correct filled)

When i try to provision (deploy) the template to another RG APIM service (clean), i am getting the following error:

New-AzResourceGroupDeployment : 13:47:24 - Resource Microsoft.ApiManagement/service/apis/policies 'apim-test/dataserviceservice/policy' failed with message '{
  "error": {
    "code": "ValidationError",
    "message": "One or more fields contain incorrect values:",
    "details": [
      {
        "code": "ValidationError",
        "target": "authentication-certificate",
        "message": "Error in element 'authentication-certificate' on line 16, column 6: Certificate with thumbprint '4xXxxXxxXxXXxXXxX6' could not be resolved."
      }
    ]
  }
}'
At C:\Users\xxx\xxx\Apim Creator\deploy.ps1:112 char:5
+     New-AzResourceGroupDeployment -ResourceGroupName $resourceGroupNa ...
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [New-AzResourceGroupDeployment], Exception
    + FullyQualifiedErrorId : Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.NewAzureResourceGroupDeploymentCmdlet

When i check the status in APIM for the API's:

  • All API's are deployed
  • First API SOAP service is coupled to Client Certificate (backend is protected with certificate) except the second API SOAP service.

Strange thing is that, when i ran the script second time, deployment went successfully without errors. And it fixes the second API SOAP Service (this time backend coupled with Client Certificate).

(Every first time failing and second time successfully. Tried many times with different RG APIM Services)

Do you have any idea? Your help will be appreciated.

Add logger support

It would be great if there were logger support to App Insights. Here's an example of how we've done it:

{
    "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "api-name": {
            "type": "string",
            "minLength": 1
        },
        "instrumentationKey": {
            "type": "string",
            "minLength": 1
        },
        "subscription": {
            "defaultValue": "dev",
            "type": "string",
            "allowedValues": [
                "sandbox",
                "dev",
                "test",
                "production"
            ]
        }
    },
    "variables": {
        "api-logger-name": "[concat(parameters('api-name'), '-', parameters('subscription'), '-logger')]",
        "apiM-name": "[concat('apiManagement-', parameters('subscription'), '-apimanager')]",
        "instrumentationKey": "[parameters('instrumentationKey')]"
    },
    "resources": [

// LOGGER
        {
            "type": "Microsoft.ApiManagement/service/loggers",
            "name": "[concat(variables('apiM-name'), '/', variables('api-logger-name'))]",
            "apiVersion": "2018-06-01-preview",
            "tags": {
                "displayName": "logger"
            },
            "properties": {
                "loggerType": "applicationInsights",
                "credentials": {
                    "instrumentationKey": "[variables('instrumentationKey')]"
                },
                "isBuffered": true
            }
        },

// API
        {
            "type": "Microsoft.ApiManagement/service/apis",
            "name": "api-name",
            "apiVersion": "2018-01-01",
            "properties": {
            },
            "resources": [

// LOGGER ASSOCIATION WITH API
                {
                    "name": "applicationinsights",
                    "type": "diagnostics",
                    "apiVersion": "2018-06-01-preview",
                    "properties": {
                        "enabled": true,
                        "loggerId": "[resourceId('Microsoft.ApiManagement/service/loggers', variables('apiM-name'), variables('api-logger-name'))]"
                    },
                    "resources": [],
                    "dependsOn": [
                        "[resourceId('Microsoft.ApiManagement/service/apis', variables('apiM-name'), variables('api-v1-name'))]"
                    ]
                }
            ]
        }
    ]
}

Hopefully I got that right. I combined two different templates we had and tried to clean it up to show the relevant parts.

API Filters not working

Not sure, if this is an issue with the code. I was able to previously successfully generate API templates following the steps described. But this time around I have been trying to make this work for hours now but it keeps giving me below error.

_Get-APIManagementTemplate : Aggregation Exception thrown, One or more errors occurred., first Exception message is: Object reference not set to an instance of an object., for more information read the output file.
At line:1 char:1

  • Get-APIManagementTemplate -APIManagement ccauapid01 -APIFilters "pro ...
  •   + CategoryInfo          : NotSpecified: (:) [Get-APIManagementTemplate], Exception
      + FullyQualifiedErrorId : System.Exception,APIManagementTemplate.GeneratorCmdlet_
    
    

below is the powershell command.

Get-APIManagementTemplate -APIManagement api-dev -APIFilters "productname eq 'xxxx-api'" -ResourceGroup api-dev-rg01 -SubscriptionId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -ExportPIManagementInstance $false | Out-File C:\temp\APItemplate.json

Named values used in backend definitions

DependsOn not set

When defining a backend and use a named value, that named value is extracted in the template. So far so good.
But that backend is not set to depend on the same named value, leading to errors in deployment since the backend might be deployed before the named value is. Manually updating the template made it work just fine.

Original template code

(deleted some for readability)

{
      "type": "Microsoft.ApiManagement/service/backends",
      "name": "[concat(parameters('My_API_Service_name'), '/' ,'LogicAppName')]",
      "apiVersion": "2019-01-01",
      "properties": {
        "url": "Long tings pointing to a logic app in this case",
        "resourceId": "Pointing to said logic app",
        "credentials": {
          "query": {
            "sig": [
              "{{MyLogicAppKey}}"
            ]
          },
          "header": {}
        },
      "dependsOn": []
    },
    {
      "type": "Microsoft.ApiManagement/service/namedValues",
      "name": "[concat(parameters('My_API_Service_name'), '/', 'MyLogicAppKey')]",
      "apiVersion": "2020-06-01-preview",
      "properties": {
        "displayName": "MyLogicAppKey",
        "secret": true,
        "value": "A long thing pointing to the signature in the Logic app"
      },
      "resources": [],
      "dependsOn": []
    }

My updated template code

(Just the affected part the post is getting too long)

{
      "type": "Microsoft.ApiManagement/service/backends",
      "name": "[concat(parameters('My_API_Service_name'), '/' ,'LogicAppName')]",
      "apiVersion": "2019-01-01",
      "properties": {
        "url": "Long tings pointing to a logic app in this case",
        "resourceId": "Pointing to said logic app",
        "credentials": {
          "query": {
            "sig": [
              "{{MyLogicAppKey}}"
            ]
          },
          "header": {}
        },
      "dependsOn": [
        "[resourceId('Microsoft.ApiManagement/service/namedValues', parameters('My_API_Service_name'), 'MyLogicAppKey')]"
      ]
    },

Support for KeyVault

In the latest version , properties marked "secret" get a default value of "secretvalue" instead of the actual value. This makes sense, but it means a manual step after deployment when this tool is used in a CI/CD pipeline (we use this tool for deployments from DEV to TEST).

A possible solution would be to use a KeyVault for secrets. But this requires 2 changes:

  • An option to create a parameter file.
  • An option to specify a KeyVault name.

'The resource 'Microsoft.ApiManagement/service/APIMINSTANCENAME/groups/administrators' is not defined in the template

Hi,

I am new to this module and I installed the PowerShell module and generated the APIM ARM template via following statement:
Get-APIManagementTemplate -APIFilters $filter -APIManagement $apimanagementname -ResourceGroup $resourcegroupname -SubscriptionId $Subscriptionid -TenantName $TenantName -ExportPIManagementInstance $false -ExportGroups $false | Out-File $TemplateFilePath

When I try to provision the ARM template I am getting the following error :
When I omit the -ExportGroups flag (which default value is true) it results in the same error.

Any ideas?

New-AzResourceGroupDeployment : 13:27:19 - Error: Code=InvalidTemplate; Message=Deployment template validation failed:
'The resource 'Microsoft.ApiManagement/service/APIMINSTANCENAME/groups/administrators' is not defined in the template. Ple
ase see https://aka.ms/arm-template for usage details.'.
At \deploy.ps1:112 char:5

  • New-AzResourceGroupDeployment -ResourceGroupName $resourceGroupNa ...
    
  • ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : NotSpecified: (:) [New-AzResourceGroupDeployment], Exception
    • FullyQualifiedErrorId : Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.NewAzureResourceGroupDep
      loymentCmdlet

PolicyHandeAzureResources does not work correct

PolicyHandeAzureResources depends on comment with is added when selecting a for example a Logic App. This comment is not added anymore. Please reengineer this logic

Comment what is missing looks like this:
<!-- { "azureResource": { "type": "logicapp", "id": "/subscriptions/c107df29-a4af-4bc9-a733-f88f0eaa4296/resourceGroups/PreDemoTest/providers/Microsoft.Logic/workflows/INT001-GetOrderInfo/triggers/request" } } -->

Execution Error

Command:

Get-APIManagementTemplate -APIManagement API-MANAGEMENT-DEV -ResourceGroup API-WEU-D -SubscriptionId xxxxe93f-xxxx-4f6c-xxxx-94376bexxxxx | Out-File c:\tmp\template.json

Answer:
Get-APIManagementTemplate : Aggregation Exception thrown, Mindestens ein Fehler ist aufgetreten., first Exception
message is: Die Länge darf nicht kleiner als 0 (null) sein.
Parametername: length, for more information read the output file.
In Zeile:1 Zeichen:1
Get-APIManagementTemplate -APIManagement API-MANAGEMENT-DEV -Reso ...
CategoryInfo : NotSpecified: (:) [Get-APIManagementTemplate], Exception
FullyQualifiedErrorId : System.Exception,APIManagementTemplate.GeneratorCmdlet

In File:
Aggregation exception thrown, se following exceptions for more information Exception: Die Länge darf nicht kleiner als 0 (null) sein. Parametername: length bei System.String.Substring(Int32 startIndex, Int32 length) bei APIManagementTemplate.TemplateGenerator.<GenerateTemplate>d__16.MoveNext()

Deployment failure due to new property subscriptionRequired

Hi!

Looks like MS added a new field in the API settings called "Subscription required".

When i deploy a generated template with this property i get the following error: "SubscriptionRequired property is not supported for versions before 20180601"

I just removed it from the generated template and it worked again.

Best regards,
Ludvig Falck

Products with API acccess - Using a parameter that is not included in the ARM-Template

Trying to export API Management after creating a product with access to APIs.

The resouce type: Microsoft.ApiManagement/service/products/groups, are then dependent on the API, but the api name is parameterized with a parameter that don't exists.

{ "comments": "Generated for resource /subscriptions/8a4a2401-585c-4a02-a2cb-30dbe70723d1/resourceGroups/nip-dev-rg/providers/Microsoft.ApiManagement/service/<name>/products/<groupName>/groups/administrators", "type": "Microsoft.ApiManagement/service/products/groups", "name": "[concat(parameters('service_<apim_name>'), '/', '<groupName>', '/', 'administrators')]", "apiVersion": "2019-01-01", "properties": { "displayName": "Administrators", "description": "Administrators is a built-in group. Its membership is managed by the system. Microsoft Azure subscription administrators fall into this group.", "builtIn": true, "type": "system", "externalId": null }, "resources": [], "dependsOn": [ "[resourceId('Microsoft.ApiManagement/service/products', parameters(service_<apim_name>), <groupName>)]" ] } ], "dependsOn": [ "[resourceId('Microsoft.ApiManagement/service', parameters(service_<apim_name>))]", "[resourceId('Microsoft.ApiManagement/service/apis', parameters('service_<apim_name>), parameters(api_<apiName>))]" ]

The parameter api_apiName does not exist.

Write-APIManagementTemplates: AlwaysAddPropertiesAndBackend + GenerateParameterFiles causes causes cast error

When running this command: Write-APIManagementTemplates -OutputDirectory "C:\Users\me\someplaceonmymachine" -SeparatePolicyFile $true -SeparateSwaggerFile $true -GenerateParameterFiles $true -AlwaysAddPropertiesAndBackend $true

I get this error: Write-APIManagementTemplates : Cannot cast Newtonsoft.Json.Linq.JObject to Newtonsoft.Json.Linq.JToken

This only happens when I refer to a Backend by id. It doesn't seem to matter which Backend type or cert etc.

I tried creating a minimal repro, but of course it is not complete since then the extractor won't work. If you wish to use it, make sure to add <set-backend-service backend-id="Test" /> in the <inbound>-block: repro.zip.

Further, it seems that this issue only occurs when I combine AlwaysAddPropertiesAndBackend and GenerateParameterFiles. If either is missing, the script proceeds just fine. Admittedly, I haven't looked deeply into what these parameters actually do. Particularily AlwaysAddPropertiesAndBackend might be misused here, but since there is no validation rule stopping me, and I up until now have just been mindlessly using what a colleague offered me, it took a fair share of troubleshooting to reach this state.

Hope this issue is clear and actionable. If not, let me know if I can provide any further information.

Extract Specific Operation from APIM

@MLogdberg
Is there any way, we can extract specific operation from APIM ?
I can extract either full APIM configuration or till API level which consists of more than one operation.

I am using below powershell script.

$apimName = 'demo-apim'
$rgName = 'RG-Demo'
$subId = 'XXX-XXX-XXX-XXX'
$tenant = 'XXX.com'
$apiName = "path eq 'order'"
$filename = 'C:\Users\Desktop\term\' + $apimName + '.json'
Get-APIManagementTemplate -APIManagement $apimName -ResourceGroup $rgName -SubscriptionId $subId -TenantName $tenant -APIFilters $apiName -ExportPIManagementInstance $false | Out-File $filename

Hardcoded api name in the api-product registration

Ran into another hardcoding issue for api-product registration that caused deployment to fail.

This is the name for the api-product registration:
"[concat(parameters('service_apim_name'), '/', parameters('product_name'), '/HARDCODED_API_NAME')]"

The name of the api at the end should be parameterized.

I'll get started on a PR for this.

Backend function key should be parameterized

Currently, the function key value is not getting parameterized for a backend. It's using listsecrets, which will fail because it can't be used to retrieve a host key. I have a PR fix for this. I have added this as an optional parameter (default false), because I don't want to assume this is how everyone will want to use it.

AzureResourceCollector returning resources with the wrong type

I just started getting this issue today. Here's an example. Resources of type "Microsoft.ApiManagement/service/apis/operations/policies" are coming back as "Microsoft.ApiManagement/service/apis/operations".

Can you confirm you're getting this or not?

Support for Powershell 7

When running the powershell command in Powershell 7.X we encounter the following error:
image

If we run the same command in Powershell 5 then it works fine.

Will there be support for Powershell 7?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.