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

Parametrize backend proxy #787

Merged
merged 2 commits into from
Aug 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/ArmTemplates/Common/Constants/GlobalConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public static class ParameterNames
public const string SecretValues = "secretValues";
public const string IdentityProvidersSecretValues = "identityProviders";
public const string OpenIdConnectProvidersSecretValues = "openIdConnectProviders";
public const string BackendProxy = "backendProxy";
}

public static class ParameterPrefix
Expand All @@ -54,5 +55,6 @@ public static class ParameterPrefix
public const string LogResourceId = "LogResourceId";
public const string Backend = "Backend";
public const string ApiOauth2Scope = "ApiOauth2Scope";
public const string BackendProxy = "BackendProxy";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// --------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// --------------------------------------------------------------------------

namespace Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common.Templates.Backend
{
public class BackendProxyParameters
{
public string Url { get; set; }

public string Username { get; set; }

public string Password { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public class BackendTemplateResources : ITemplateResources

public IDictionary<string, BackendApiParameters> BackendNameParametersCache { get; set; } = new Dictionary<string, BackendApiParameters>();

public IDictionary<string, BackendProxyParameters> BackendProxyParametersCache { get; set; } = new Dictionary<string, BackendProxyParameters>();

public TemplateResource[] BuildTemplateResources()
{
return this.Backends.ToArray();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public TemplateBuilder AddParameterizedBackendSettings(ExtractorParameters extra
Type = "object"
};
this.template.Parameters.Add(ParameterNames.BackendSettings, extractBackendParametersProperties);
this.template.Parameters.Add(ParameterNames.BackendProxy, extractBackendParametersProperties);
}

return this;
Expand Down
21 changes: 21 additions & 0 deletions src/ArmTemplates/Extractor/EntityExtractors/BackendExtractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,27 @@ void SaveBackendApiParametersToCache()
{
backendTemplate.TypedResources.BackendNameParametersCache.Add(backendValidName, backendApiParameters);
}

if (backendResource.Properties.Proxy != null)
{
var proxyUniqueId = $"{backendResource.Properties.Proxy.Url}_{backendResource.Properties.Proxy.Username}";
DeagleGross marked this conversation as resolved.
Show resolved Hide resolved
var backendProxyParameterName = NamingHelper.GenerateValidParameterName(proxyUniqueId, ParameterPrefix.BackendProxy);

if (!backendTemplate.TypedResources.BackendProxyParametersCache.ContainsKey(backendProxyParameterName))
{
var backendProxyParameters = new BackendProxyParameters
{
Url = backendResource.Properties.Proxy.Url,
Username = backendResource.Properties.Proxy.Username,
Password = backendResource.Properties.Proxy.Password
};
backendTemplate.TypedResources.BackendProxyParametersCache.Add(backendProxyParameterName, backendProxyParameters);
}

backendResource.Properties.Proxy.Url = $"[parameters('{ParameterNames.BackendProxy}').{backendProxyParameterName}.url]";
backendResource.Properties.Proxy.Username = $"[parameters('{ParameterNames.BackendProxy}').{backendProxyParameterName}.username]";
backendResource.Properties.Proxy.Password = $"[parameters('{ParameterNames.BackendProxy}').{backendProxyParameterName}.password]";
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,9 @@ public Template<MasterTemplateResources> GenerateLinkedMasterTemplate(
{
backendsDeployment.Properties.Parameters.Add(ParameterNames.BackendSettings,
new TemplateParameterProperties() { Value = $"[parameters('{ParameterNames.BackendSettings}')]" });

backendsDeployment.Properties.Parameters.Add(ParameterNames.BackendProxy,
new TemplateParameterProperties() { Value = $"[parameters('{ParameterNames.BackendProxy}')]" });
}

masterResources.DeploymentResources.Add(backendsDeployment);
Expand Down Expand Up @@ -497,6 +500,10 @@ Dictionary<string, TemplateParameterProperties> CreateMasterTemplateParameters(E
parameters.Add(
ParameterNames.BackendSettings,
new TemplateParameterProperties(metadataDescription: "The settings for the Backends", type: "object"));

parameters.Add(
ParameterNames.BackendProxy,
new TemplateParameterProperties(metadataDescription: "The proxies for the Backends", type: "object"));
}

if (extractorParameters.ParametrizeApiOauth2Scope)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ async Task AddSecretValuesParameters()
if (extractorParameters.ParameterizeBackend)
{
parameters.Add(ParameterNames.BackendSettings, new TemplateObjectParameterProperties() { Value = backendResources.BackendNameParametersCache });
parameters.Add(ParameterNames.BackendProxy, new TemplateObjectParameterProperties() { Value = backendResources.BackendProxyParametersCache });
DeagleGross marked this conversation as resolved.
Show resolved Hide resolved
}

return parametersTemplate;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ public async Task GenerateAllCurrentApiReleaseTemplateAsync_ProperlyCreatesTempl
apiReleasesTemplate.TypedResources.ApiReleases.Any(x => x.Properties.ApiId.Contains($"/apis/echo-api;rev=1")).Should().BeTrue();
apiReleasesTemplate.TypedResources.ApiReleases.Any(x => x.Properties.ApiId.Contains($"/apis/5a7390baa5816a110435aee0;rev=1")).Should().BeTrue();
apiReleasesTemplate.TypedResources.ApiReleases.Any(x => x.Properties.ApiId.Contains($"/apis/5a73933b8f27f7cc82a2d533;rev=1")).Should().BeTrue();

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public async Task GenerateBackendTemplates_ProperlyLaysTheInformation()

backendTemplate.Parameters.Should().ContainKey(ParameterNames.ApimServiceName);
backendTemplate.Parameters.Should().ContainKey(ParameterNames.BackendSettings);
backendTemplate.Parameters.Should().ContainKey(ParameterNames.BackendProxy);

backendTemplate.TypedResources.Backends.Should().HaveCount(1);
backendTemplate.Resources.Should().HaveCount(1);
Expand All @@ -83,6 +84,61 @@ public async Task GenerateBackendTemplates_ProperlyLaysTheInformation()
backendProperties.Should().NotBeNull();
backendProperties.Url.Should().Contain(ParameterNames.BackendSettings);
backendProperties.Protocol.Should().Contain(ParameterNames.BackendSettings);

backendProperties.Proxy.Password.Should().Contain(ParameterNames.BackendProxy);
backendProperties.Proxy.Username.Should().Contain(ParameterNames.BackendProxy);
backendProperties.Proxy.Url.Should().Contain(ParameterNames.BackendProxy);
}

[Fact]
public async Task GenerateBackendTemplate_ProperlyParsesAndGeneratesTemplate()
{
// arrange
var responseFileLocation = Path.Combine(MockClientUtils.ApiClientJsonResponsesPath, "ApiManagementListBackends_success_response.json");
var currentTestDirectory = Path.Combine(this.OutputDirectory, nameof(GenerateBackendTemplate_ProperlyParsesAndGeneratesTemplate));

var mockedClient = await MockBackendClient.GetMockedHttpApiClient(responseFileLocation);

var extractorConfig = this.GetDefaultExtractorConsoleAppConfiguration(
apiName: string.Empty,
paramBackend: "true");
var extractorParameters = new ExtractorParameters(extractorConfig);

// mocked extractors
var backendExtractor = new BackendExtractor(
this.GetTestLogger<BackendExtractor>(),
new TemplateBuilder(),
null,
mockedClient);

var extractorExecutor = ExtractorExecutor.BuildExtractorExecutor(
this.GetTestLogger<ExtractorExecutor>(),
backendExtractor: backendExtractor);
extractorExecutor.SetExtractorParameters(extractorParameters);

// act
var backendTemplate = await extractorExecutor.GenerateBackendTemplateAsync(null, null, null, currentTestDirectory);

// assert
File.Exists(Path.Combine(currentTestDirectory, extractorParameters.FileNames.Backends)).Should().BeTrue();

backendTemplate.Parameters.Should().ContainKey(ParameterNames.ApimServiceName);
backendTemplate.Parameters.Should().ContainKey(ParameterNames.BackendSettings);
backendTemplate.Parameters.Should().ContainKey(ParameterNames.BackendProxy);


backendTemplate.TypedResources.Backends.Count().Should().Be(3);
backendTemplate.TypedResources.Backends.All(x => x.Type.Equals(ResourceTypeConstants.Backend)).Should().BeTrue();

var proxyBackend1 = backendTemplate.TypedResources.Backends.First(x => x.Name.Contains("proxybackend1"));
proxyBackend1.Properties.Proxy.Password.Should().Contain(ParameterNames.BackendProxy);
proxyBackend1.Properties.Proxy.Username.Should().Contain(ParameterNames.BackendProxy);
proxyBackend1.Properties.Proxy.Url.Should().Contain(ParameterNames.BackendProxy);

var proxyBackend2 = backendTemplate.TypedResources.Backends.First(x => x.Name.Contains("proxybackend2"));
proxyBackend2.Properties.Proxy.Password.Should().Contain(ParameterNames.BackendProxy);
proxyBackend2.Properties.Proxy.Username.Should().Contain(ParameterNames.BackendProxy);
proxyBackend2.Properties.Proxy.Url.Should().Contain(ParameterNames.BackendProxy);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ public async Task GenerateMasterTemplates_ProperlyLaysTheInformation()
masterTemplate.Parameters.Should().ContainKey(ParameterNames.LoggerResourceId);
masterTemplate.Parameters.Should().ContainKey(ParameterNames.NamedValueKeyVaultSecrets);
masterTemplate.Parameters.Should().ContainKey(ParameterNames.BackendSettings);
masterTemplate.Parameters.Should().ContainKey(ParameterNames.BackendProxy);
masterTemplate.Parameters.Should().ContainKey(ParameterNames.PolicyXMLBaseUrl);
masterTemplate.Parameters.Should().ContainKey(ParameterNames.PolicyXMLBaseUrl);
masterTemplate.Parameters.Should().ContainKey(ParameterNames.ApiOauth2ScopeSettings);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common.Templates.IdentityProviders;
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Tests.Moqs.IdentityProviderClients;
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common.Templates.OpenIdConnectProviders;
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common.Templates.Backend;

namespace Microsoft.Azure.Management.ApiManagement.ArmTemplates.Tests.Extractor.Scenarios
{
Expand Down Expand Up @@ -432,5 +433,63 @@ public void CreateResourceTemplateParameterTemplate_ProperlyGeneratesTemplate_Wi
resourceTemplateParameterTemplate.Parameters["parameter1"].Should().NotBeNull();
resourceTemplateParameterTemplate.Parameters["parameter2"].Should().NotBeNull();
}

[Fact]
public async Task CreateResourceTemplateParameterTemplate_ProperlyGeneratesTemplate_WithBackendProxySettings()
{
// arrange
var currentTestDirectory = Path.Combine(this.OutputDirectory, nameof(CreateResourceTemplateParameterTemplate_ProperlyGeneratesTemplate_WithBackendProxySettings));

var extractorConfig = this.GetDefaultExtractorConsoleAppConfiguration(paramBackend: "true");
var extractorParameters = new ExtractorParameters(extractorConfig);
var extractorExecutor = this.GetExtractorInstance(extractorParameters, null);

var backends = new BackendTemplateResources()
{
BackendNameParametersCache = new Dictionary<string, BackendApiParameters>()
{
{ "key1", new BackendApiParameters() { Protocol = "protocol", ResourceId = "resourceId", Url = "url" } }
},
BackendProxyParametersCache = new Dictionary<string, BackendProxyParameters>()
{
{ "key1", new BackendProxyParameters() { Username = "username", Url = "url" } }
},
Backends = new List<BackendTemplateResource>()
{
{
new BackendTemplateResource
{
Name = "test"
}
}
}
};

// act
var parametersTemplate = await extractorExecutor.GenerateParametersTemplateAsync(null, null, backends, null, new IdentityProviderResources(), new OpenIdConnectProviderResources(), currentTestDirectory);

File.Exists(Path.Combine(currentTestDirectory, extractorParameters.FileNames.Parameters)).Should().BeTrue();

parametersTemplate.Parameters.Should().ContainKey(ParameterNames.BackendProxy);
parametersTemplate.Parameters.Should().ContainKey(ParameterNames.BackendSettings);

var backendProxyParameters = (TemplateObjectParameterProperties)parametersTemplate.Parameters[ParameterNames.BackendProxy];
var backendProxyParameterValues = (Dictionary<string, BackendProxyParameters>)backendProxyParameters.Value;

backendProxyParameterValues.Should().NotBeNull();
backendProxyParameterValues.ContainsKey("key1").Should().BeTrue();
backendProxyParameterValues["key1"].Username.Should().Be("username");
backendProxyParameterValues["key1"].Url.Should().Be("url");


var backendSettingsParameters = (TemplateObjectParameterProperties)parametersTemplate.Parameters[ParameterNames.BackendSettings];
var backendSettingsParameterValues = (Dictionary<string, BackendApiParameters>)backendSettingsParameters.Value;

backendSettingsParameterValues.Should().NotBeNull();
DeagleGross marked this conversation as resolved.
Show resolved Hide resolved
backendSettingsParameterValues.ContainsKey("key1").Should().BeTrue();
backendSettingsParameterValues["key1"].Protocol.Should().Be("protocol");
backendSettingsParameterValues["key1"].ResourceId.Should().Be("resourceId");
backendSettingsParameterValues["key1"].Url.Should().Be("url");
}
}
}
10 changes: 10 additions & 0 deletions tests/ArmTemplates.Tests/Moqs/ApiClients/MockBackendClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
// --------------------------------------------------------------------------

using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common.API.Clients.Abstractions;
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common.API.Clients.Backend;
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common.Templates.Backend;
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Extractor.Models;
using Moq;
Expand Down Expand Up @@ -43,5 +45,13 @@ public static IBackendClient GetMockedApiClientWithDefaultValues()

return mockBackendClient.Object;
}

public static async Task<IBackendClient> GetMockedHttpApiClient(string responseFileLocation)
{
var mockedClient = new Mock<BackendClient>(MockBehavior.Strict, await MockClientUtils.GenerateMockedIHttpClientFactoryWithResponse(responseFileLocation));
MockClientUtils.MockAuthOfApiClient(mockedClient);

return mockedClient.Object;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
{
"value": [
{
"id": "/subscriptions/subid/resourceGroups/rg1/providers/Microsoft.ApiManagement/service/apimService1/backends/proxybackend1",
"type": "Microsoft.ApiManagement/service/backends",
"name": "proxybackend1",
"properties": {
"description": "description5308",
"url": "https://backendname2644/",
"protocol": "http",
"credentials": {
"query": {
"sv": [
"xx",
"bb",
"cc"
]
},
"header": {
"x-my-1": [
"val1",
"val2"
]
},
"authorization": {
"scheme": "Basic",
"parameter": "opensesma"
}
},
"proxy": {
"url": "http://192.168.1.1:8080",
"username": "Contoso\\admin",
"password": "<password>"
},
"tls": {
"validateCertificateChain": false,
"validateCertificateName": false
}
}
},
{
"id": "/subscriptions/subid/resourceGroups/rg1/providers/Microsoft.ApiManagement/service/apimService1/backends/proxybackend2",
"type": "Microsoft.ApiManagement/service/backends",
"name": "proxybackend2",
"properties": {
"description": "description5308",
"url": "https://backendname2644/",
"protocol": "http",
"credentials": {
"query": {
"sv": [
"xx",
"bb",
"cc"
]
},
"header": {
"x-my-1": [
"val1",
"val2"
]
},
"authorization": {
"scheme": "Basic",
"parameter": "opensesma"
}
},
"proxy": {
"url": "http://192.168.1.1:8080",
"username": "Contoso\\admin",
"password": "<password>"
},
"tls": {
"validateCertificateChain": false,
"validateCertificateName": false
}
}
},
{
"id": "/subscriptions/subid/resourceGroups/rg1/providers/Microsoft.ApiManagement/service/apimService1/backends/sfbackend",
"type": "Microsoft.ApiManagement/service/backends",
"name": "sfbackend",
"properties": {
"description": "Service Fabric Test App 1",
"url": "fabric:/mytestapp/mytestservice",
"protocol": "http",
"properties": {
"serviceFabricCluster": {
"managementEndpoints": [
"https://somecluster.com"
],
"clientCertificateId": "/subscriptions/subid/resourceGroups/rg1/providers/Microsoft.ApiManagement/service/apimService1/certificates/cert1",
"serverX509Names": [
{
"name": "ServerCommonName1",
"issuerCertificateThumbprint": "IssuerCertificateThumbprint1"
}
],
"maxPartitionResolutionRetries": 5
}
}
}
}
],
"count": 3
}