Skip to content

Commit

Permalink
Bug fixes to #354 Update Template Validator to understand ApiProfiles…
Browse files Browse the repository at this point in the history
… and #237 & #367 Test-AzureRMTemplate output string contains incorrect report file path (#486)
  • Loading branch information
deepaft authored and knithinc committed Jan 9, 2019
1 parent d985ce8 commit e7c7c9c
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 21 deletions.
73 changes: 72 additions & 1 deletion CloudCapabilities/AzureRM.CloudCapabilities.psm1
Expand Up @@ -14,33 +14,104 @@ function Get-AzureRMCloudCapability() {
[CmdletBinding()]
[OutputType([string])]
Param(
[Parameter(ParameterSetName = "local")]
[Parameter(ParameterSetName = "url")]
[Parameter(HelpMessage = 'Json output file')]
[String] $OutputPath = "AzureCloudCapabilities.Json",

[Parameter(ParameterSetName = "local")]
[Parameter(ParameterSetName = "url")]
[Parameter(HelpMessage = 'Cloud Capabilities for the specified location')]
[String] $Location,

[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")]
[ValidateScript( { Test-Path -Path $_ })]
[String] $ApiProfilePath,

[Parameter(HelpMessage = "Url pointing to the location of the supported api profiles", ParameterSetName = "url")]
[String] $ApiProfilesUrl = "https://api.github.com/repos/Azure/azure-rest-api-specs/contents/profile",

[Parameter(ParameterSetName = "local")]
[Parameter(ParameterSetName = "url")]
[Parameter(HelpMessage = 'Set this to get compute resource provider Capabilities like Extensions, Images, Sizes')]
[Switch] $IncludeComputeCapabilities,

[Parameter(ParameterSetName = "local")]
[Parameter(ParameterSetName = "url")]
[Parameter(HelpMessage = 'Set this to get storage resource provider Capabilities like Sku')]
[Switch] $IncludeStorageCapabilities
)

$sw = [Diagnostics.Stopwatch]::StartNew()
Write-Verbose "Getting CloudCapabilities for location: '$location'"

$rootPath = $env:TEMP
$fileDir = "ApiProfiles"
$localDirPath = Join-Path -Path $rootPath -ChildPath $fileDir
if(Test-Path($localDirPath))
{
Remove-Item -Path $localDirPath -Recurse -Force -ErrorAction Stop
}
New-Item -Path $rootPath -Name $fileDir -ItemType "directory"
if ($PSCmdlet.ParameterSetName -eq "url")
{
Write-Verbose "Downloading api profile jsons from '$ApiProfilesUrl'"
try {
$content = Invoke-RestMethod -Method GET -UseBasicParsing -Uri $ApiProfilesUrl
$webClient = [System.Net.WebClient]::new()
foreach( $c in $content) {
$destPath = Join-Path -Path $localDirPath -ChildPath $c.name
$webClient.DownloadFile($c.download_url, $destPath)
}
}
catch {
$err = "Exception: Unable to get the api profile jsons. ApiProfilesUrl - $ApiProfilesUrl. $($_.Exception.Message)"
Write-Error $err
}
}
else
{
Write-Verbose "Using api profile jsons from local path: '$ApiProfilePath'"
$localDirPath = $ApiProfilePath
}
Write-Verbose "Reading api profiles jsons..."
$apiProfiles = @()
if(Test-Path($localDirPath)) {
$ApiProfilePattern = "*.json"
$ProfilesDirectory = Get-ChildItem -Path $localDirPath -Recurse -Include $ApiProfilePattern
foreach ($apiProfilejson in $ProfilesDirectory) {
$apiProfileFileName = Split-path -Path $apiProfilejson.FullName -Leaf
Write-Verbose "Reading api profile $apiProfileFileName"
$apiProfile = ConvertFrom-Json (Get-Content -Path $apiProfilejson -Raw) -ErrorAction Stop
$apiProfileName = $apiProfile.info.name
$apiProfiles += $apiProfile
}
}
else {
Write-Warning "Api profiles jsons not found!"
}

$providerNamespaces = (Get-AzureRmResourceProvider -ListAvailable -Location $location -ErrorAction Stop).ProviderNamespace
$resources = @()
foreach ($providerNamespace in $providerNamespaces) {
Write-Verbose "Working on $providerNamespace provider namespace"
try {
$resourceTypes = (Get-AzureRmResourceProvider -ProviderNamespace $providerNamespace -ErrorAction Stop).ResourceTypes
foreach ($resourceType in $resourceTypes) {
$result = "" | Select-Object ProviderNamespace, ResourceTypeName, Locations, ApiVersions
$result = "" | Select-Object ProviderNamespace, ResourceTypeName, Locations, ApiVersions, ApiProfiles
$result.ProviderNamespace = $providerNamespace
$result.ResourceTypeName = $resourceType.ResourceTypeName
$result.Locations = $resourceType.Locations
$result.ApiVersions = $resourceType.ApiVersions
$profileNames = @()
foreach ($apiProfile in $apiProfiles) {
#if $resourceType.ResourceTypeName exists in $apiProfile add $apiProfile.info.name to $profileNames
$apiProfileProviderNamespace = $apiProfile.'resource-manager'.$providerNamespace
if($null -ne ($apiProfileProviderNamespace.Psobject.Properties | % { $_.value } | ? { $_ -eq $resourceType.ResourceTypeName } )) {
$profileNames += $apiProfile.info.name
}
}
$result.ApiProfiles = $profileNames
$resources += , $result
}
}
Expand Down
72 changes: 52 additions & 20 deletions TemplateValidator/AzureRM.TemplateValidator.psm1
Expand Up @@ -43,6 +43,7 @@ function Test-AzureRMTemplate() {
)

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

if ($PSCmdlet.ParameterSetName -eq "url")
{
Expand Down Expand Up @@ -172,7 +173,7 @@ function Test-AzureRMTemplate() {
$reportOutPut += $templateResults
}
if (([System.IO.FileInfo]$Report).Extension -eq '.csv') {
$reportOutPut | Export-CSV -delimiter ';' -NoTypeInformation -Encoding "unicode" -Path $Report
$reportOutPut | Export-CSV -delimiter ';' -NoTypeInformation -Encoding "unicode" -Path $reportFilePath
}
elseif (([System.IO.FileInfo]$Report).Extension -eq '.html') {
$head = @"
Expand Down Expand Up @@ -242,9 +243,8 @@ table td:nth-child(3){white-space:pre-line}
}
}
$reportHtml = $title + $validationSummary + $reportXml.OuterXml|Out-String
ConvertTo-Html $postContent -head $head -Body $reportHtml | out-File $Report
ConvertTo-Html $postContent -head $head -Body $reportHtml | out-File $reportFilePath
}
$reportFilePath = Join-Path $PSScriptRoot $Report
Write-Output "Validation Summary:
`Passed: $passedCount
`NotSupported: $notSupportedCount
Expand Down Expand Up @@ -674,27 +674,59 @@ function ValidateResource {
$resourceOutput += $msg
}
else {
Write-Verbose "Validating API version for $ResourceProviderNameSpace\$ResourceTypeName"
try {
$templateResApiversion = $resource.apiversion
$templateResApiversionType = GetPropertyType $templateResApiversion
if ($templateResApiversionType -eq "function") {
$msg = "Recommend: apiVersion (Resource type: $($resource.type)). It is recommended to set it as a literal value."
Write-Warning $msg
$resourceOutput += $msg
}
$templateResApiversion = Get-PropertyValue $templateResApiversion $Template $resource
$supportedApiVersions = $ResourceTypeProperties.Apiversions
$notSupported = CompareValues $templateResApiversion $supportedApiVersions
if ($notSupported) {
if ($notSupported.NoneSupported) {
$msg = "NotSupported: apiversion (Resource type: $($resource.type)). Not Supported Values - $($notSupported.NotSupportedValues)"
if($templateResApiversion) {
Write-Verbose "Validating API version for $ResourceProviderNameSpace\$ResourceTypeName"
$templateResApiversionType = GetPropertyType $templateResApiversion
if ($templateResApiversionType -eq "function") {
$msg = "Recommend: apiVersion (Resource type: $($resource.type)). It is recommended to set it as a literal value."
Write-Warning $msg
$resourceOutput += $msg
}
else {
$msg = "Warning: apiversion (Resource type: $($resource.type)). Not Supported Values - $($notSupported.NotSupportedValues)"
$templateResApiversion = Get-PropertyValue $templateResApiversion $Template $resource
$supportedApiVersions = $ResourceTypeProperties.Apiversions
$notSupported = CompareValues $templateResApiversion $supportedApiVersions
if ($notSupported) {
if ($notSupported.NoneSupported) {
$msg = "NotSupported: apiversion (Resource type: $($resource.type)). Not Supported Values - $($notSupported.NotSupportedValues)"
}
else {
$msg = "Warning: apiversion (Resource type: $($resource.type)). Not Supported Values - $($notSupported.NotSupportedValues)"
}
Write-Warning $msg
$resourceOutput += $msg
}
Write-Warning $msg
$resourceOutput += $msg
}
else {
$templateResApiProfileVersion = $Template.apiProfile
if( -not $templateResApiProfileVersion) {
$msg = "Exception: apiVersion and apiProfile for resource of type $ResourceTypeName is not specified. One of them has to be specified. "
Write-Error $msg
$resourceOutput += $msg
}
else {
Write-Verbose "Validating API profile version for $ResourceProviderNameSpace\$ResourceTypeName"
$supportedApiProfileVersions = $ResourceTypeProperties.ApiProfiles
if( -not $supportedApiProfileVersions) {
$msg = "NotSupported: No supported api profile versions for this resource, $ResourceProviderNameSpace\$ResourceTypeName."
Write-Warning $msg
$resourceOutput += $msg
}
else{
$notSupported = CompareValues $templateResApiProfileVersion $supportedApiProfileVersions
if ($notSupported) {
if ($notSupported.NoneSupported) {
$msg = "NotSupported: api profile version for (Resource type: $($resource.type)). Not Supported Values - $($notSupported.NotSupportedValues)"
}
else {
$msg = "Warning: apiversion (Resource type: $($resource.type)). Not Supported Values - $($notSupported.NotSupportedValues)"
}
Write-Warning $msg
$resourceOutput += $msg
}
}
}
}
}
catch {
Expand Down

0 comments on commit e7c7c9c

Please sign in to comment.