Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Commit

Permalink
Fixed deploying multiple versions of the same API (#575)
Browse files Browse the repository at this point in the history
* '#562 - Supports deploying multiple versions of an api sequentially.

* #562 - Fixed odd conflict on existing path when deploying multiple versions of the same api.

Co-authored-by: Maxime LABELLE <[email protected]>
  • Loading branch information
springcomp and Maxime LABELLE authored Sep 13, 2021
1 parent 7911271 commit 254a260
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 6 deletions.
8 changes: 6 additions & 2 deletions src/APIM_ARMTemplate/apimtemplate/Commands/Create.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ public CreateCommand()
List<Template> apiTemplates = new List<Template>();
Console.WriteLine("Creating API templates");
Console.WriteLine("------------------------------------------");

IDictionary<string, string[]> apiVersions = APITemplateCreator.GetApiVersionSets(creatorConfig);

foreach (APIConfig api in creatorConfig.apis)
{
if (considerAllApiForDeployments || preferredApis.Contains(api.name))
Expand All @@ -155,7 +158,8 @@ public CreateCommand()
name = api.name,
isSplit = apiTemplateCreator.isSplitAPI(api),
dependsOnGlobalServicePolicies = creatorConfig.policy != null,
dependsOnVersionSets = api.apiVersionSetId != null,
dependsOnVersionSets = api.apiVersionSetId != null,
dependsOnVersion = masterTemplateCreator.GetDependsOnPreviousApiVersion(api, apiVersions),
dependsOnProducts = api.products != null,
dependsOnTags = api.tags != null,
dependsOnLoggers = await masterTemplateCreator.DetermineIfAPIDependsOnLoggerAsync(api, fileReader),
Expand Down Expand Up @@ -234,4 +238,4 @@ public CreateCommand()
});
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using apimtemplate.Creator.Utilities;
using System.Net;
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Extract;
using System.Linq;

namespace Microsoft.Azure.Management.ApiManagement.ArmTemplates.Create
{
Expand Down Expand Up @@ -238,7 +239,20 @@ public async Task<APITemplateResource> CreateAPITemplateResourceAsync(APIConfig
}
apiTemplateResource.properties.format = format;
apiTemplateResource.properties.value = value;
apiTemplateResource.properties.path = api.suffix;

// #562: deploying multiple versions of an API may fail because while trying to deploy the initial template
// overwrite the initial template’s path property to a dummy value
// this value will be restored when the subsequent template is deployed

if (isSplit && isInitial)
{
apiTemplateResource.properties.path = api.suffix + $"/{Guid.NewGuid():n}";
}
else
{
apiTemplateResource.properties.path = api.suffix;
}

if (!String.IsNullOrEmpty(api.serviceUrl))
{
apiTemplateResource.properties.serviceUrl = MakeServiceUrl(api);
Expand All @@ -247,6 +261,22 @@ public async Task<APITemplateResource> CreateAPITemplateResourceAsync(APIConfig
return apiTemplateResource;
}

internal static IDictionary<string, string[]> GetApiVersionSets(CreatorConfig creatorConfig)
{
var apiVersions = (creatorConfig.apiVersionSets ?? new List<APIVersionSetConfig>())
.ToDictionary(v => v.id, v => new List<string>())
;

foreach (var api in creatorConfig.apis.Where(a => !string.IsNullOrEmpty(a.apiVersionSetId)))
apiVersions[api.apiVersionSetId].Add(api.name)
;

return apiVersions.ToDictionary(
kv => kv.Key,
kv => kv.Value.OrderBy(v => v).ToArray()
);
}

private static string GetOpenApiSpecFormat(bool isUrl, bool isJSON, bool isVersionThree)
{
return isUrl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public Template CreateLinkedMasterTemplate(CreatorConfig creatorConfig,

string initialAPIFileName = fileNameGenerator.GenerateCreatorAPIFileName(apiInfo.name, apiInfo.isSplit, true);
string initialAPIUri = GenerateLinkedTemplateUri(creatorConfig, initialAPIFileName);
string[] initialAPIDependsOn = CreateAPIResourceDependencies(globalServicePolicyTemplate, apiVersionSetTemplate, productsTemplate, loggersTemplate, backendsTemplate, authorizationServersTemplate, tagTemplate, apiInfo, previousAPIName);
string[] initialAPIDependsOn = CreateAPIResourceDependencies(creatorConfig, globalServicePolicyTemplate, apiVersionSetTemplate, productsTemplate, loggersTemplate, backendsTemplate, authorizationServersTemplate, tagTemplate, apiInfo, previousAPIName);
resources.Add(this.CreateLinkedMasterTemplateResource(initialAPIDeploymentResourceName, initialAPIUri, initialAPIDependsOn, originalAPIName, apiInfo.isServiceUrlParameterize));

string subsequentAPIFileName = fileNameGenerator.GenerateCreatorAPIFileName(apiInfo.name, apiInfo.isSplit, false);
Expand All @@ -128,7 +128,7 @@ public Template CreateLinkedMasterTemplate(CreatorConfig creatorConfig,
string unifiedAPIDeploymentResourceName = $"{originalAPIName}-APITemplate";
string unifiedAPIFileName = fileNameGenerator.GenerateCreatorAPIFileName(apiInfo.name, apiInfo.isSplit, true);
string unifiedAPIUri = GenerateLinkedTemplateUri(creatorConfig, unifiedAPIFileName);
string[] unifiedAPIDependsOn = CreateAPIResourceDependencies(globalServicePolicyTemplate, apiVersionSetTemplate, productsTemplate, loggersTemplate, backendsTemplate, authorizationServersTemplate, tagTemplate, apiInfo, previousAPIName);
string[] unifiedAPIDependsOn = CreateAPIResourceDependencies(creatorConfig, globalServicePolicyTemplate, apiVersionSetTemplate, productsTemplate, loggersTemplate, backendsTemplate, authorizationServersTemplate, tagTemplate, apiInfo, previousAPIName);
resources.Add(this.CreateLinkedMasterTemplateResource(unifiedAPIDeploymentResourceName, unifiedAPIUri, unifiedAPIDependsOn, originalAPIName, apiInfo.isServiceUrlParameterize));

// Set previous API name for dependency chain
Expand All @@ -140,7 +140,9 @@ public Template CreateLinkedMasterTemplate(CreatorConfig creatorConfig,
return masterTemplate;
}

public string[] CreateAPIResourceDependencies(Template globalServicePolicyTemplate,
public string[] CreateAPIResourceDependencies(
CreatorConfig creatorConfig,
Template globalServicePolicyTemplate,
Template apiVersionSetTemplate,
Template productsTemplate,
Template loggersTemplate,
Expand Down Expand Up @@ -179,6 +181,10 @@ public string[] CreateAPIResourceDependencies(Template globalServicePolicyTempla
{
apiDependsOn.Add("[resourceId('Microsoft.Resources/deployments', 'tagTemplate')]");
}
if (apiInfo.dependsOnVersion != null)
{
apiDependsOn.Add($"[resourceId('Microsoft.Resources/deployments', '{apiInfo.dependsOnVersion}-SubsequentAPITemplate')]");
}
if (previousAPI != null && apiInfo.dependsOnTags == true)
{
apiDependsOn.Add($"[resourceId('Microsoft.Resources/deployments', '{previousAPI}')]");
Expand Down Expand Up @@ -240,6 +246,32 @@ public MasterTemplateResource CreateLinkedMasterTemplateResource(string name, st
return masterTemplateResource;
}

public string GetDependsOnPreviousApiVersion(APIConfig api, IDictionary<string, string[]> apiVersions)
{
if (api?.apiVersionSetId == null)
return null;

// get all apis associated with the same versionSet
// versions must be deployed in sequence and thus
// each api must depend on the previous version.

var versions = apiVersions.ContainsKey(api.apiVersionSetId)
? apiVersions[api.apiVersionSetId]
: null
;

var index = Array.IndexOf(versions, api.name);
var previous = index > 0
? (int?)index - 1
: null
;

return previous.HasValue
? versions[previous.Value]
: null
;
}

public Dictionary<string, TemplateParameterProperties> CreateMasterTemplateParameters(CreatorConfig creatorConfig)
{
// used to create the parameter metatadata, etc (not value) for use in file with resources
Expand Down Expand Up @@ -417,6 +449,7 @@ public class LinkedMasterTemplateAPIInformation
public bool dependsOnAuthorizationServers { get; set; }
public bool dependsOnTags { get; set; }
public bool isServiceUrlParameterize { get; set; }
public string dependsOnVersion { get; set; }
}

}

0 comments on commit 254a260

Please sign in to comment.