Skip to content

Commit e7c7c9c

Browse files
deepaftknithinc
authored andcommitted
Bug fixes to #354 Update Template Validator to understand ApiProfiles and #237 & #367 Test-AzureRMTemplate output string contains incorrect report file path (#486)
1 parent d985ce8 commit e7c7c9c

File tree

2 files changed

+124
-21
lines changed

2 files changed

+124
-21
lines changed

CloudCapabilities/AzureRM.CloudCapabilities.psm1

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,33 +14,104 @@ function Get-AzureRMCloudCapability() {
1414
[CmdletBinding()]
1515
[OutputType([string])]
1616
Param(
17+
[Parameter(ParameterSetName = "local")]
18+
[Parameter(ParameterSetName = "url")]
1719
[Parameter(HelpMessage = 'Json output file')]
1820
[String] $OutputPath = "AzureCloudCapabilities.Json",
1921

22+
[Parameter(ParameterSetName = "local")]
23+
[Parameter(ParameterSetName = "url")]
2024
[Parameter(HelpMessage = 'Cloud Capabilities for the specified location')]
2125
[String] $Location,
2226

27+
[Parameter(Mandatory = $true, HelpMessage = "Directory containing api profile jsons for the supported api profiles. Use this parameter when running in a disconnected environment. Please save the api profile jsons from https://github.com/Azure/azure-rest-api-specs/tree/master/profile to a local directory and pass the location.", ParameterSetName = "local")]
28+
[ValidateScript( { Test-Path -Path $_ })]
29+
[String] $ApiProfilePath,
30+
31+
[Parameter(HelpMessage = "Url pointing to the location of the supported api profiles", ParameterSetName = "url")]
32+
[String] $ApiProfilesUrl = "https://api.github.com/repos/Azure/azure-rest-api-specs/contents/profile",
33+
34+
[Parameter(ParameterSetName = "local")]
35+
[Parameter(ParameterSetName = "url")]
2336
[Parameter(HelpMessage = 'Set this to get compute resource provider Capabilities like Extensions, Images, Sizes')]
2437
[Switch] $IncludeComputeCapabilities,
2538

39+
[Parameter(ParameterSetName = "local")]
40+
[Parameter(ParameterSetName = "url")]
2641
[Parameter(HelpMessage = 'Set this to get storage resource provider Capabilities like Sku')]
2742
[Switch] $IncludeStorageCapabilities
2843
)
2944

3045
$sw = [Diagnostics.Stopwatch]::StartNew()
3146
Write-Verbose "Getting CloudCapabilities for location: '$location'"
47+
48+
$rootPath = $env:TEMP
49+
$fileDir = "ApiProfiles"
50+
$localDirPath = Join-Path -Path $rootPath -ChildPath $fileDir
51+
if(Test-Path($localDirPath))
52+
{
53+
Remove-Item -Path $localDirPath -Recurse -Force -ErrorAction Stop
54+
}
55+
New-Item -Path $rootPath -Name $fileDir -ItemType "directory"
56+
if ($PSCmdlet.ParameterSetName -eq "url")
57+
{
58+
Write-Verbose "Downloading api profile jsons from '$ApiProfilesUrl'"
59+
try {
60+
$content = Invoke-RestMethod -Method GET -UseBasicParsing -Uri $ApiProfilesUrl
61+
$webClient = [System.Net.WebClient]::new()
62+
foreach( $c in $content) {
63+
$destPath = Join-Path -Path $localDirPath -ChildPath $c.name
64+
$webClient.DownloadFile($c.download_url, $destPath)
65+
}
66+
}
67+
catch {
68+
$err = "Exception: Unable to get the api profile jsons. ApiProfilesUrl - $ApiProfilesUrl. $($_.Exception.Message)"
69+
Write-Error $err
70+
}
71+
}
72+
else
73+
{
74+
Write-Verbose "Using api profile jsons from local path: '$ApiProfilePath'"
75+
$localDirPath = $ApiProfilePath
76+
}
77+
Write-Verbose "Reading api profiles jsons..."
78+
$apiProfiles = @()
79+
if(Test-Path($localDirPath)) {
80+
$ApiProfilePattern = "*.json"
81+
$ProfilesDirectory = Get-ChildItem -Path $localDirPath -Recurse -Include $ApiProfilePattern
82+
foreach ($apiProfilejson in $ProfilesDirectory) {
83+
$apiProfileFileName = Split-path -Path $apiProfilejson.FullName -Leaf
84+
Write-Verbose "Reading api profile $apiProfileFileName"
85+
$apiProfile = ConvertFrom-Json (Get-Content -Path $apiProfilejson -Raw) -ErrorAction Stop
86+
$apiProfileName = $apiProfile.info.name
87+
$apiProfiles += $apiProfile
88+
}
89+
}
90+
else {
91+
Write-Warning "Api profiles jsons not found!"
92+
}
93+
3294
$providerNamespaces = (Get-AzureRmResourceProvider -ListAvailable -Location $location -ErrorAction Stop).ProviderNamespace
3395
$resources = @()
3496
foreach ($providerNamespace in $providerNamespaces) {
3597
Write-Verbose "Working on $providerNamespace provider namespace"
3698
try {
3799
$resourceTypes = (Get-AzureRmResourceProvider -ProviderNamespace $providerNamespace -ErrorAction Stop).ResourceTypes
38100
foreach ($resourceType in $resourceTypes) {
39-
$result = "" | Select-Object ProviderNamespace, ResourceTypeName, Locations, ApiVersions
101+
$result = "" | Select-Object ProviderNamespace, ResourceTypeName, Locations, ApiVersions, ApiProfiles
40102
$result.ProviderNamespace = $providerNamespace
41103
$result.ResourceTypeName = $resourceType.ResourceTypeName
42104
$result.Locations = $resourceType.Locations
43105
$result.ApiVersions = $resourceType.ApiVersions
106+
$profileNames = @()
107+
foreach ($apiProfile in $apiProfiles) {
108+
#if $resourceType.ResourceTypeName exists in $apiProfile add $apiProfile.info.name to $profileNames
109+
$apiProfileProviderNamespace = $apiProfile.'resource-manager'.$providerNamespace
110+
if($null -ne ($apiProfileProviderNamespace.Psobject.Properties | % { $_.value } | ? { $_ -eq $resourceType.ResourceTypeName } )) {
111+
$profileNames += $apiProfile.info.name
112+
}
113+
}
114+
$result.ApiProfiles = $profileNames
44115
$resources += , $result
45116
}
46117
}

TemplateValidator/AzureRM.TemplateValidator.psm1

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ function Test-AzureRMTemplate() {
4343
)
4444

4545
$capabilities = ConvertFrom-Json (Get-Content -Path $CapabilitiesPath -Raw) -ErrorAction Stop
46+
$reportFilePath = Join-Path $PSScriptRoot $Report
4647

4748
if ($PSCmdlet.ParameterSetName -eq "url")
4849
{
@@ -172,7 +173,7 @@ function Test-AzureRMTemplate() {
172173
$reportOutPut += $templateResults
173174
}
174175
if (([System.IO.FileInfo]$Report).Extension -eq '.csv') {
175-
$reportOutPut | Export-CSV -delimiter ';' -NoTypeInformation -Encoding "unicode" -Path $Report
176+
$reportOutPut | Export-CSV -delimiter ';' -NoTypeInformation -Encoding "unicode" -Path $reportFilePath
176177
}
177178
elseif (([System.IO.FileInfo]$Report).Extension -eq '.html') {
178179
$head = @"
@@ -242,9 +243,8 @@ table td:nth-child(3){white-space:pre-line}
242243
}
243244
}
244245
$reportHtml = $title + $validationSummary + $reportXml.OuterXml|Out-String
245-
ConvertTo-Html $postContent -head $head -Body $reportHtml | out-File $Report
246+
ConvertTo-Html $postContent -head $head -Body $reportHtml | out-File $reportFilePath
246247
}
247-
$reportFilePath = Join-Path $PSScriptRoot $Report
248248
Write-Output "Validation Summary:
249249
`Passed: $passedCount
250250
`NotSupported: $notSupportedCount
@@ -674,27 +674,59 @@ function ValidateResource {
674674
$resourceOutput += $msg
675675
}
676676
else {
677-
Write-Verbose "Validating API version for $ResourceProviderNameSpace\$ResourceTypeName"
678677
try {
679678
$templateResApiversion = $resource.apiversion
680-
$templateResApiversionType = GetPropertyType $templateResApiversion
681-
if ($templateResApiversionType -eq "function") {
682-
$msg = "Recommend: apiVersion (Resource type: $($resource.type)). It is recommended to set it as a literal value."
683-
Write-Warning $msg
684-
$resourceOutput += $msg
685-
}
686-
$templateResApiversion = Get-PropertyValue $templateResApiversion $Template $resource
687-
$supportedApiVersions = $ResourceTypeProperties.Apiversions
688-
$notSupported = CompareValues $templateResApiversion $supportedApiVersions
689-
if ($notSupported) {
690-
if ($notSupported.NoneSupported) {
691-
$msg = "NotSupported: apiversion (Resource type: $($resource.type)). Not Supported Values - $($notSupported.NotSupportedValues)"
679+
if($templateResApiversion) {
680+
Write-Verbose "Validating API version for $ResourceProviderNameSpace\$ResourceTypeName"
681+
$templateResApiversionType = GetPropertyType $templateResApiversion
682+
if ($templateResApiversionType -eq "function") {
683+
$msg = "Recommend: apiVersion (Resource type: $($resource.type)). It is recommended to set it as a literal value."
684+
Write-Warning $msg
685+
$resourceOutput += $msg
692686
}
693-
else {
694-
$msg = "Warning: apiversion (Resource type: $($resource.type)). Not Supported Values - $($notSupported.NotSupportedValues)"
687+
$templateResApiversion = Get-PropertyValue $templateResApiversion $Template $resource
688+
$supportedApiVersions = $ResourceTypeProperties.Apiversions
689+
$notSupported = CompareValues $templateResApiversion $supportedApiVersions
690+
if ($notSupported) {
691+
if ($notSupported.NoneSupported) {
692+
$msg = "NotSupported: apiversion (Resource type: $($resource.type)). Not Supported Values - $($notSupported.NotSupportedValues)"
693+
}
694+
else {
695+
$msg = "Warning: apiversion (Resource type: $($resource.type)). Not Supported Values - $($notSupported.NotSupportedValues)"
696+
}
697+
Write-Warning $msg
698+
$resourceOutput += $msg
695699
}
696-
Write-Warning $msg
697-
$resourceOutput += $msg
700+
}
701+
else {
702+
$templateResApiProfileVersion = $Template.apiProfile
703+
if( -not $templateResApiProfileVersion) {
704+
$msg = "Exception: apiVersion and apiProfile for resource of type $ResourceTypeName is not specified. One of them has to be specified. "
705+
Write-Error $msg
706+
$resourceOutput += $msg
707+
}
708+
else {
709+
Write-Verbose "Validating API profile version for $ResourceProviderNameSpace\$ResourceTypeName"
710+
$supportedApiProfileVersions = $ResourceTypeProperties.ApiProfiles
711+
if( -not $supportedApiProfileVersions) {
712+
$msg = "NotSupported: No supported api profile versions for this resource, $ResourceProviderNameSpace\$ResourceTypeName."
713+
Write-Warning $msg
714+
$resourceOutput += $msg
715+
}
716+
else{
717+
$notSupported = CompareValues $templateResApiProfileVersion $supportedApiProfileVersions
718+
if ($notSupported) {
719+
if ($notSupported.NoneSupported) {
720+
$msg = "NotSupported: api profile version for (Resource type: $($resource.type)). Not Supported Values - $($notSupported.NotSupportedValues)"
721+
}
722+
else {
723+
$msg = "Warning: apiversion (Resource type: $($resource.type)). Not Supported Values - $($notSupported.NotSupportedValues)"
724+
}
725+
Write-Warning $msg
726+
$resourceOutput += $msg
727+
}
728+
}
729+
}
698730
}
699731
}
700732
catch {

0 commit comments

Comments
 (0)