Skip to content

Commit

Permalink
Added support for Azure resources deployment with Bicep language
Browse files Browse the repository at this point in the history
  • Loading branch information
BethanyZhou committed Feb 4, 2021
1 parent 2eddc95 commit a0a48f0
Show file tree
Hide file tree
Showing 11 changed files with 5,227 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,21 @@
// limitations under the License.
// ----------------------------------------------------------------------------------

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using Microsoft.Azure.Commands.Common.Authentication;
using Microsoft.Azure.Commands.Common.Authentication.Abstractions;
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Components;
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Utilities;
using Microsoft.Azure.Management.ResourceManager;
using Microsoft.WindowsAzure.Commands.Utilities.Common;

using Newtonsoft.Json.Linq;

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;

namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation
{
public abstract class ResourceWithParameterCmdletBase : ResourceManagerCmdletBase
Expand Down Expand Up @@ -168,6 +170,8 @@ public ITemplateSpecsClient TemplateSpecsClient

public object GetDynamicParameters()
{
RedirectToStandardARMTemplateFile();

if (!this.IsParameterBound(c => c.SkipTemplateParameterPrompt))
{
// Resolve the static parameter names for this cmdlet:
Expand Down Expand Up @@ -399,5 +403,20 @@ protected string[] GetStaticParameterNames()
CmdletInfo cmdletInfo = new CmdletInfo(commandName, this.GetType());
return cmdletInfo.Parameters.Keys.ToArray();
}

/// <summary>
/// Redirect the input template file to standard ARM json template file.
/// </summary>
protected void RedirectToStandardARMTemplateFile()
{
if (BicepUtility.IsBicepFile(TemplateFile) && FileUtilities.DataStore.FileExists(TemplateFile))
{
TemplateFile = BicepUtility.BuildFile(this.ExecuteScript<Object>, TemplateFile);
}
else if(BicepUtility.IsBicepFile(TemplateUri) && Uri.IsWellFormedUriString(TemplateUri, UriKind.Absolute))
{
TemplateUri = BicepUtility.BuildFile(this.ExecuteScript<Object>, TemplateUri);
}
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/Resources/ResourceManager/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -494,4 +494,7 @@ You can help us improve the accuracy of the result by opening an issue here: htt
<data name="InvalidChangeType" xml:space="preserve">
<value>Unrecognized resource change {0}: {1}. Specify one ore more values in the following list and try again: {2}.</value>
</data>
<data name="BicepNotFound" xml:space="preserve">
<value>Cannot find Bicep. Please add Bicep to your PATH or visit https://github.com/Azure/bicep/releases to install Bicep.</value>
</data>
</root>
79 changes: 79 additions & 0 deletions src/Resources/ResourceManager/Utilities/BicepUtility.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// ----------------------------------------------------------------------------------
//
// Copyright Microsoft Corporation
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------------------------------------------------------------

using Microsoft.Azure.Commands.Common.Authentication.Abstractions;
using Microsoft.Azure.Commands.Common.Exceptions;
using Microsoft.WindowsAzure.Commands.Utilities.Common;

using System;
using System.Collections.Generic;
using System.IO;

namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.Utilities
{
public static class BicepUtility
{
public static bool IsBicepExecutable { get; private set; } = false;

public static bool IsBicepFile(string templateFilePath)
{
return ".bicep".Equals(Path.GetExtension(templateFilePath), System.StringComparison.OrdinalIgnoreCase);
}

public delegate List<T> ScriptExecutor<T>(string script);

public static bool CheckBicepExecutable<T>(ScriptExecutor<T> executeScript)
{
try
{
executeScript("get-command bicep");
}
catch
{
IsBicepExecutable = false;
return IsBicepExecutable;
}
IsBicepExecutable = true;
return IsBicepExecutable;
}

public static string BuildFile<T>(ScriptExecutor<T> executeScript, string bicepTemplateFilePath)
{
if (!IsBicepExecutable && !CheckBicepExecutable(executeScript))
{
throw new AzPSApplicationException(Properties.Resources.BicepNotFound);
}

string tempPath = Path.Combine(Path.GetTempPath(), Path.GetFileName(bicepTemplateFilePath));

try{
if (Uri.IsWellFormedUriString(bicepTemplateFilePath, UriKind.Absolute))
{
FileUtilities.DataStore.WriteFile(tempPath, GeneralUtilities.DownloadFile(bicepTemplateFilePath));
}
else if (FileUtilities.DataStore.FileExists(bicepTemplateFilePath))
{
File.Copy(bicepTemplateFilePath, tempPath, true);
}
executeScript($"bicep build '{tempPath}'");
return tempPath.Replace(".bicep", ".json");
}
finally
{
File.Delete(tempPath);
}

}
}
}
2 changes: 2 additions & 0 deletions src/Resources/Resources.Test/Resources.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@

<ItemGroup>
<None Update="Resources\*.json" CopyToOutputDirectory="PreserveNewest" />
<None Update="Resources\*.bicep" CopyToOutputDirectory="PreserveNewest" />
<None Update="*.json" CopyToOutputDirectory="PreserveNewest" />
<None Update="*.bicep" CopyToOutputDirectory="PreserveNewest" />
<None Update="ScenarioTests\*.pfx" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

Expand Down
14 changes: 14 additions & 0 deletions src/Resources/Resources.Test/ScenarioTests/DeploymentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,5 +155,19 @@ public void TestNewDeploymentWithQueryString()
{
TestRunner.RunTestScript("Test-NewDeploymentWithQueryString");
}

[Fact]
[Trait(Category.AcceptanceType, Category.LiveOnly)]
public void TestNewDeploymentFromBicepFile()
{
TestRunner.RunTestScript("Test-NewDeploymentFromBicepFile");
}

[Fact]
[Trait(Category.AcceptanceType, Category.LiveOnly)]
public void TestTestDeploymentFromBicepFile()
{
TestRunner.RunTestScript("Test-TestDeploymentFromBicepFile");
}
}
}
67 changes: 66 additions & 1 deletion src/Resources/Resources.Test/ScenarioTests/DeploymentTests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -662,12 +662,77 @@ function Test-NewDeploymentWithQueryString

# Assert
Assert-AreEqual Succeeded $deployment.ProvisioningState

}

finally
{
# Cleanup
Clean-ResourceGroup $rgname
}
}

<#
.SYNOPSIS
Tests deployment via Bicep file.
#>
function Test-NewDeploymentFromBicepFile
{
# Setup
$rgname = Get-ResourceGroupName
$rname = Get-ResourceName
$rglocation = "West US 2"
$expectedTags = @{"key1"="value1"; "key2"="value2";}

try
{
# Test
New-AzResourceGroup -Name $rgname -Location $rglocation

$deployment = New-AzResourceGroupDeployment -Name $rname -ResourceGroupName $rgname -TemplateFile sampleDeploymentBicepFile.bicep -Tag $expectedTags

# Assert
Assert-AreEqual Succeeded $deployment.ProvisioningState
Assert-True { AreHashtableEqual $expectedTags $deployment.Tags }

$subId = (Get-AzContext).Subscription.SubscriptionId
$deploymentId = "/subscriptions/$subId/resourcegroups/$rgname/providers/Microsoft.Resources/deployments/$rname"
$getById = Get-AzResourceGroupDeployment -Id $deploymentId
Assert-AreEqual $getById.DeploymentName $deployment.DeploymentName

[hashtable]$actualTags = $getById.Tags
Assert-True { AreHashtableEqual $expectedTags $getById.Tags }
}
finally
{
# Cleanup
Clean-ResourceGroup $rgname
}
}

<#
.SYNOPSIS
Tests deployment template via bicep file.
#>
function Test-TestDeploymentFromBicepFile
{
# Setup
$rgname = Get-ResourceGroupName
$rname = Get-ResourceName
$location = "West US 2"

# Test
try
{
New-AzResourceGroup -Name $rgname -Location $location

$list = Test-AzResourceGroupDeployment -ResourceGroupName $rgname -TemplateFile sampleDeploymentBicepFile.bicep

# Assert
Assert-AreEqual 0 @($list).Count
}
finally
{
# Cleanup
Clean-ResourceGroup $rgname
}
}
Loading

0 comments on commit a0a48f0

Please sign in to comment.