* initial push of ntier iaas modules

* added azure bastion subnet

* updated landing zone dependencies, added topological sort

* added topological sort implementation

* added project file

* added newtonsoft package

* added todo comment

* added circular reference verification on topological sort

* moved landing zone to its own folder. added domain join extension to vm template

* added joined to domain extension on VMSS

* renamed sql server always on template and added join domain extension in vmss

* fixed unit test

* fixed all unit tests

* added IIS template

* added parameters to ntier-iaas archetype

* finished orchestration of ntier-iaas

* fixed unit test

* added missing files

* updated parameter values

* fix access token retrieval

* added missing module definitions
This commit is contained in:
Jorge Cotillo 2019-08-23 22:31:50 -07:00 коммит произвёл Kungumaraj Nachimuthu
Родитель 51b3710985
Коммит e514547774
101 изменённых файлов: 8230 добавлений и 2794 удалений

Просмотреть файл

@ -13,4 +13,7 @@ Environments/
tests/
roles/
Config/
Agent/
Agent/
*.dll
*.deps.json
*.pdb

4
.gitignore поставляемый
Просмотреть файл

@ -49,7 +49,9 @@ app_creds_real.py
*.sln.docstates
.vs/
.vscode
*.dll
*.pdb
*.deps.json
# Windows image file caches
Thumbs.db
ehthumbs.db

Просмотреть файл

@ -26,5 +26,5 @@
]
}
],
"DnsServers": "reference(${Parameters.Organization}-shrdsvcs.ActiveDirectoryDomainServices.dnsServers)"
"DnsServers": "reference(${Parameters.Organization}-shrdsvcs.InstallActiveDirectoryDomainServices.dnsServers)"
}

Просмотреть файл

@ -3,6 +3,7 @@
"ModuleConfigurations": [
{
"Name": "SubscriptionCreation",
"Enabled": false,
"Script": {
"Command": "../../../Scripts/Subscription/NewSubscription.ps1",
"Arguments": {
@ -51,6 +52,9 @@
"Name": "LogAnalytics",
"ModuleDefinitionName": "LogAnalytics",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.LogAnalytics.ResourceGroup}",
"DependsOn": [
"DiagnosticStorageAccount"
],
"Deployment": {
"OverrideParameters": {
"logAnalyticsWorkspaceName": {
@ -74,6 +78,9 @@
{
"Name": "AzureSecurityCenter",
"ModuleDefinitionName": "AzureSecurityCenter",
"DependsOn": [
"LogAnalytics"
],
"Deployment": {
"OverrideParameters": {
"workspaceId": {
@ -85,6 +92,9 @@
{
"Name": "NISTControls",
"ModuleDefinitionName": "NISTControls",
"DependsOn": [
"LogAnalytics"
],
"Deployment": {
"OverrideParameters": {
"workspaceId": {
@ -100,6 +110,10 @@
"Name": "DefaultNSG",
"ModuleDefinitionName": "NetworkSecurityGroups",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.NetworkSecurityGroups.ResourceGroup}",
"DependsOn": [
"DiagnosticStorageAccount",
"LogAnalytics"
],
"Deployment": {
"OverrideParameters": {
"workspaceId": {
@ -121,6 +135,7 @@
"Name": "DefaultRouteTable",
"ModuleDefinitionName": "RouteTables",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.RouteTables.ResourceGroup}",
"DependsOn": [],
"Deployment": {
"OverrideParameters": {
"routeTableName": {
@ -134,8 +149,12 @@
},
{
"Name": "VirtualNetwork",
"ModuleDefinitionName": "vNet",
"ModuleDefinitionName": "VirtualNetwork",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.ResourceGroup}",
"DependsOn": [
"DefaultNSG",
"DefaultRouteTable"
],
"Deployment": {
"OverrideParameters": {
"vnetName": {
@ -161,8 +180,11 @@
},
{
"Name": "LocalVirtualNetworkPeering",
"ModuleDefinitionName": "vNetPeering",
"ModuleDefinitionName": "VirtualNetworkPeering",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.ResourceGroup}",
"DependsOn": [
"VirtualNetwork"
],
"Deployment": {
"OverrideParameters": {
"localVnetName": {
@ -179,9 +201,12 @@
},
{
"Name": "RemoteVirtualNetworkPeering",
"ModuleDefinitionName": "vNetPeering",
"ModuleDefinitionName": "VirtualNetworkPeering",
"Subscription": "SharedServices",
"ResourceGroupName": "reference(${Parameters.Organization}-shrdsvcs.VirtualNetwork.vNetResourceGroup)",
"DependsOn": [
"VirtualNetwork"
],
"Deployment": {
"OverrideParameters": {
"localVnetName": {

Просмотреть файл

@ -5,12 +5,6 @@
"Subscription": "ASE_SQLDB",
"ModuleConfigurationParameters": {
"OnPremisesInformation": {
"ActiveDirectory": {
"PrimaryDomainControllerIP": "192.168.1.4",
"DomainName": "fontoso.com",
"ADSitename": "Cloud-Site",
"DomainAdminUserName": "fontoso"
},
"Network": {
"AddressPrefix": "192.168.1.0/28"
}

Просмотреть файл

@ -0,0 +1,5 @@
{
"Subscriptions": "env(VDC_SUBSCRIPTIONS)",
"Parameters": "file(./parameters.json)",
"Orchestration": "file(./orchestration.json)"
}

Просмотреть файл

@ -0,0 +1,483 @@
{
"ModuleConfigurationsPath": "../../../Modules",
"ModuleConfigurations": [
{
"Name": "KeyVault",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.KeyVault.ResourceGroup}",
"ModuleDefinitionName": "KeyVault",
"Deployment": {
"OverrideParameters": {
"keyVaultName": {
"value": "${Parameters.ModuleConfigurationParameters.KeyVault.Name}"
},
"accessPolicies": {
"value": "${Parameters.ModuleConfigurationParameters.KeyVault.AccessPolicies}"
},
"secretsObject": {
"value": {
"secrets": "${Parameters.ModuleConfigurationParameters.KeyVault.SecretsObject.Secrets}"
}
},
"enableVaultForDeployment": {
"value": "${Parameters.ModuleConfigurationParameters.KeyVault.EnableVaultForDeployment}"
},
"enableVaultForDiskEncryption": {
"value": "${Parameters.ModuleConfigurationParameters.KeyVault.EnableVaultForDiskEncryption}"
},
"enableVaultForTemplateDeployment": {
"value": "${Parameters.ModuleConfigurationParameters.KeyVault.EnableVaultForTemplateDeployment}"
},
"vaultSku": {
"value": "${Parameters.ModuleConfigurationParameters.KeyVault.Sku}"
},
"diagnosticStorageAccountId": {
"value": "reference(DiagnosticStorageAccount.storageAccountResourceId)"
},
"workspaceId": {
"value": "reference(LogAnalytics.logAnalyticsWorkspaceResourceId)"
},
"networkAcls": {
"value": "${Parameters.ModuleConfigurationParameters.KeyVault.NetworkAcls}"
},
"vNetId": {
"value": "reference(VirtualNetwork.vNetResourceId)"
}
}
}
},
{
"Name": "WebAppLoadBalancer",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.WebAppLoadBalancer.ResourceGroup}",
"ModuleDefinitionName": "LoadBalancers",
"Deployment": {
"OverrideParameters": {
"loadBalancerName": {
"value": "${Parameters.ModuleConfigurationParameters.WebAppLoadBalancer.Name}"
},
"loadBalancingRules": {
"value": "${Parameters.ModuleConfigurationParameters.WebAppLoadBalancer.LoadBalancingRules}"
},
"probes": {
"value": "${Parameters.ModuleConfigurationParameters.WebAppLoadBalancer.Probes}"
},
"vNetId": {
"value": "reference(VirtualNetwork.vNetResourceId)"
},
"subnetName": {
"value": "${Parameters.ModuleConfigurationParameters.WebAppLoadBalancer.SubnetName}"
}
}
}
},
{
"Name": "WebAppVMSS",
"ModuleDefinitionName": "VirtualMachineScaleSets",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.WebApp.ResourceGroup}",
"DependsOn": [
"WebAppLoadBalancer",
"KeyVault"
],
"Comments": "Creates Active Directory Domain Services VMs",
"Deployment": {
"OverrideParameters": {
"virtualMachineScaleSetsName": {
"value": "${Parameters.ModuleConfigurationParameters.WebApp.Name}"
},
"virtualMachineScaleSetsSku": {
"value": "${Parameters.ModuleConfigurationParameters.WebApp.VMSKU}"
},
"virtualMachineScaleSetsOSImage": {
"value": "${Parameters.ModuleConfigurationParameters.WebApp.OSImage}"
},
"virtualMachineScaleSetsOSType": {
"value": "${Parameters.ModuleConfigurationParameters.WebApp.OSType}"
},
"virtualMachineScaleSetsDataDisks": {
"value": "${Parameters.ModuleConfigurationParameters.WebApp.DataDisks}"
},
"loadBalancerBackendPoolId": {
"value": "reference(WebLoadBalancer.loadBalancerResourceBackendPoolId)"
},
"workspaceId": {
"value": "reference(LogAnalytics.logAnalyticsWorkspaceId)"
},
"logAnalyticsWorkspacePrimarySharedKey": {
"value": "reference(LogAnalytics.logAnalyticsPrimarySharedKey)"
},
"diagnosticsStorageAccountName": {
"value": "reference(DiagnosticStorageAccount.storageAccountName)"
},
"diagnosticsStorageAccountSasToken": {
"value": "reference(DiagnosticStorageAccount.storageAccountSasToken)"
},
"artifactsStorageAccountName": {
"value": "reference(${Parameters.Organization}-shrdsvcs.ArtifactsStorageAccount.storageAccountName)"
},
"artifactsStorageAccountSasKey": {
"value": "reference(${Parameters.Organization}-shrdsvcs.ArtifactsStorageAccount.storageAccountSasToken)"
},
"vNetId": {
"value": "reference(VirtualNetwork.vNetResourceId)"
},
"subnetName": {
"value": "${Parameters.ModuleConfigurationParameters.WebApp.SubnetName}"
},
"vmIPAddress": {
"value": "${Parameters.ModuleConfigurationParameters.WebApp.AddsIPAddressStart}"
},
"applicationSecurityGroupId": {
"value": "reference(WebASG.applicationSecurityGroupResourceId)"
},
"adminUsername": {
"value": "${Parameters.ModuleConfigurationParameters.WebApp.AdminUsername}"
},
"adminPassword": {
"reference": "${Parameters.ModuleConfigurationParameters.WebApp.AdminPassword}"
},
"domainAdminUsername": {
"value": "${Parameters.ModuleConfigurationParameters.WebApp.DomainAdminUsername}"
},
"domainAdminPassword": {
"value": "${Parameters.ModuleConfigurationParameters.WebApp.DomainAdminPassword}"
},
"domainName": {
"value": "${Parameters.ModuleConfigurationParameters.WebApp.DomainName}"
}
}
}
},
{
"Name": "IISOnWebVMSS",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.WebApp.ResourceGroup}",
"ModuleDefinitionName": "InternetInformationServices",
"DependsOn":[
"WebAppVMSS"
],
"Deployment":{
"OverrideParameters":{
"virtualMachineScaleSetsName": {
"value": "${Parameters.ModuleConfigurationParameters.WebApp.Name}"
},
"artifactsStorageAccountName": {
"value": "reference(${Parameters.Organization}-shrdsvcs.ArtifactsStorageAccount.storageAccountName)"
},
"artifactsStorageAccountSasKey": {
"value": "reference(${Parameters.Organization}-shrdsvcs.ArtifactsStorageAccount.storageAccountSasToken)"
}
}
}
},
{
"Name": "BusinessAppLoadBalancer",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.BusinessAppLoadBalancer.ResourceGroup}",
"ModuleDefinitionName": "LoadBalancers",
"Deployment": {
"OverrideParameters": {
"loadBalancerName": {
"value": "${Parameters.ModuleConfigurationParameters.BusinessAppLoadBalancer.Name}"
},
"loadBalancingRules": {
"value": "${Parameters.ModuleConfigurationParameters.BusinessAppLoadBalancer.LoadBalancingRules}"
},
"probes": {
"value": "${Parameters.ModuleConfigurationParameters.BusinessAppLoadBalancer.Probes}"
},
"vNetId": {
"value": "reference(VirtualNetwork.vNetResourceId)"
},
"subnetName": {
"value": "${Parameters.ModuleConfigurationParameters.BusinessAppLoadBalancer.SubnetName}"
}
}
}
},
{
"Name": "BusinessAppVMSS",
"ModuleDefinitionName": "VirtualMachineScaleSets",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.BusinessApp.ResourceGroup}",
"DependsOn": [
"BusinessAppLoadBalancer",
"KeyVault"
],
"Comments": "Creates Active Directory Domain Services VMs",
"Deployment": {
"OverrideParameters": {
"virtualMachineScaleSetsName": {
"value": "${Parameters.ModuleConfigurationParameters.BusinessApp.Name}"
},
"virtualMachineScaleSetsSku": {
"value": "${Parameters.ModuleConfigurationParameters.BusinessApp.VMSKU}"
},
"virtualMachineScaleSetsOSImage": {
"value": "${Parameters.ModuleConfigurationParameters.BusinessApp.OSImage}"
},
"virtualMachineScaleSetsOSType": {
"value": "${Parameters.ModuleConfigurationParameters.BusinessApp.OSType}"
},
"virtualMachineScaleSetsDataDisks": {
"value": "${Parameters.ModuleConfigurationParameters.BusinessApp.DataDisks}"
},
"loadBalancerBackendPoolId": {
"value": "reference(WebLoadBalancer.loadBalancerResourceBackendPoolId)"
},
"workspaceId": {
"value": "reference(LogAnalytics.logAnalyticsWorkspaceId)"
},
"logAnalyticsWorkspacePrimarySharedKey": {
"value": "reference(LogAnalytics.logAnalyticsPrimarySharedKey)"
},
"diagnosticsStorageAccountName": {
"value": "reference(DiagnosticStorageAccount.storageAccountName)"
},
"diagnosticsStorageAccountSasToken": {
"value": "reference(DiagnosticStorageAccount.storageAccountSasToken)"
},
"artifactsStorageAccountName": {
"value": "reference(${Parameters.Organization}-shrdsvcs.ArtifactsStorageAccount.storageAccountName)"
},
"artifactsStorageAccountSasKey": {
"value": "reference(${Parameters.Organization}-shrdsvcs.ArtifactsStorageAccount.storageAccountSasToken)"
},
"vNetId": {
"value": "reference(VirtualNetwork.vNetResourceId)"
},
"subnetName": {
"value": "${Parameters.ModuleConfigurationParameters.BusinessApp.SubnetName}"
},
"vmIPAddress": {
"value": "${Parameters.ModuleConfigurationParameters.BusinessApp.AddsIPAddressStart}"
},
"applicationSecurityGroupId": {
"value": "reference(BusinessASG.applicationSecurityGroupResourceId)"
},
"adminUsername": {
"value": "${Parameters.ModuleConfigurationParameters.BusinessApp.AdminUsername}"
},
"adminPassword": {
"reference": "${Parameters.ModuleConfigurationParameters.BusinessApp.AdminPassword}"
},
"domainAdminUsername": {
"value": "${Parameters.ModuleConfigurationParameters.BusinessApp.DomainAdminUsername}"
},
"domainAdminPassword": {
"value": "${Parameters.ModuleConfigurationParameters.BusinessApp.DomainAdminPassword}"
},
"domainName": {
"value": "${Parameters.ModuleConfigurationParameters.BusinessApp.DomainName}"
}
}
}
},
{
"Name": "IISOnBusinessVMSS",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.BusinessApp.ResourceGroup}",
"ModuleDefinitionName": "InternetInformationServices",
"DependsOn":[
"BusinessAppVMSS"
],
"Deployment":{
"OverrideParameters":{
"virtualMachineScaleSetsName": {
"value": "${Parameters.ModuleConfigurationParameters.BusinessApp.Name}"
},
"artifactsStorageAccountName": {
"value": "reference(${Parameters.Organization}-shrdsvcs.ArtifactsStorageAccount.storageAccountName)"
},
"artifactsStorageAccountSasKey": {
"value": "reference(${Parameters.Organization}-shrdsvcs.ArtifactsStorageAccount.storageAccountSasToken)"
}
}
}
},
{
"Name": "SQLServerAlwaysOnLoadBalancer",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOnLoadBalancer.ResourceGroup}",
"ModuleDefinitionName": "LoadBalancers",
"Deployment": {
"OverrideParameters": {
"loadBalancerName": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOnLoadBalancer.Name}"
},
"loadBalancingRules": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOnLoadBalancer.LoadBalancingRules}"
},
"probes": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOnLoadBalancer.Probes}"
},
"vNetId": {
"value": "reference(VirtualNetwork.vNetResourceId)"
},
"loadBalancerIPAddress": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOnLoadBalancer.IPAddressStart}"
},
"subnetName": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOnLoadBalancer.SubnetName}"
}
}
}
},
{
"Name": "SQLServerAlwaysOnVMs",
"ModuleDefinitionName": "VirtualMachines",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.ResourceGroup}",
"DependsOn": [
"KeyVault",
"SQLServerAlwaysOnLoadBalancer"
],
"Comments": "Creates Active Directory Domain Services VMs",
"Deployment": {
"OverrideParameters": {
"virtualMachineName": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.Name}"
},
"virtualMachineSize": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.VMSize}"
},
"virtualMachineOSImage": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.OSImage}"
},
"virtualMachineOSType": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.OSType}"
},
"virtualMachineCount": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.VMCount}"
},
"virtualMachineDataDisks": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.DataDisks}"
},
"workspaceId": {
"value": "reference(LogAnalytics.logAnalyticsWorkspaceId)"
},
"logAnalyticsWorkspaceId": {
"value": "reference(LogAnalytics.logAnalyticsWorkspaceResourceId)"
},
"logAnalyticsWorkspacePrimarySharedKey": {
"value": "reference(LogAnalytics.logAnalyticsPrimarySharedKey)"
},
"diagnosticsStorageAccountId": {
"value": "reference(DiagnosticStorageAccount.storageAccountResourceId)"
},
"diagnosticsStorageAccountName": {
"value": "reference(DiagnosticStorageAccount.storageAccountName)"
},
"diagnosticsStorageAccountSasToken": {
"value": "reference(DiagnosticStorageAccount.storageAccountSasToken)"
},
"artifactsStorageAccountName": {
"value": "reference(${Parameters.Organization}-shrdsvcs.ArtifactsStorageAccount.storageAccountName)"
},
"artifactsStorageAccountKey": {
"value": "reference(${Parameters.Organization}-shrdsvcs.ArtifactsStorageAccount.storageAccountAccessKey)"
},
"artifactsStorageAccountSasKey": {
"value": "reference(${Parameters.Organization}-shrdsvcs.ArtifactsStorageAccount.storageAccountSasToken)"
},
"vNetId": {
"value": "reference(VirtualNetwork.vNetResourceId)"
},
"subnetName": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.SubnetName}"
},
"vmIPAddress": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.IPAddressStart}"
},
"applicationSecurityGroupId": {
"value": "reference(DataASG.applicationSecurityGroupResourceId)"
},
"adminUsername": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.AdminUsername}"
},
"adminPassword": {
"reference": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.AdminPassword}"
},
"domainAdminUsername": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.DomainAdminUsername}"
},
"domainAdminPassword": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.DomainAdminPassword}"
},
"domainName": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.DomainName}"
}
}
}
},
{
"Name": "CloudWitnessStorageAccount",
"ModuleDefinitionName": "StorageAccounts",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOnCloudWitness.ResourceGroup}",
"Comments": "Storage Account that is used as a Cloud Witness",
"Deployment": {
"Comments": "We need the 'update' module instance to lock this resource after the Virtual Network got created",
"OverrideParameters": {
"storageAccountName": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOnCloudWitness.Name}"
},
"storageAccountSku": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOnCloudWitness.Sku}"
},
"networkAcls": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOnCloudWitness.NetworkAcls}"
},
"vNetId": {
"value": "reference(VirtualNetwork.vNetResourceId)"
}
}
}
},
{
"Name": "InstallSQLServerAlwaysOn",
"ModuleDefinitionName": "VirtualMachines",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.ResourceGroup}",
"DependsOn": [
"KeyVault",
"SQLServerAlwaysOnLoadBalancer",
"CloudWitnessStorageAccount"
],
"Comments": "Creates Active Directory Domain Services VMs",
"Deployment": {
"OverrideParameters": {
"virtualMachineName": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.Name}"
},
"adminUsername": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.Name}"
},
"adminPassword": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.Name}"
},
"clusterName": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.Name}"
},
"artifactsStorageAccountName": {
"value": "reference(${Parameters.Organization}-shrdsvcs.ArtifactsStorageAccount.storageAccountName)"
},
"artifactsStorageAccountKey": {
"value": "reference(${Parameters.Organization}-shrdsvcs.ArtifactsStorageAccount.storageAccountAccessKey)"
},
"artifactsStorageAccountSasKey": {
"value": "reference(${Parameters.Organization}-shrdsvcs.ArtifactsStorageAccount.storageAccountSasToken)"
},
"cloudWitnessStorageAccountName": {
"value": "reference(CloudWitnessStorageAccount.storageAccountName)"
},
"cloudWitnessStorageAccountKey": {
"value": "reference(CloudWitnessStorageAccount.storageAccountName)"
},
"sqlServerILB_IPAddress": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.Name}"
},
"domainName": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.Name}"
},
"domainAdminUsername": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.Name}"
},
"domainAdminPassword": {
"value": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.Name}"
}
}
}
}
]
}

Просмотреть файл

@ -0,0 +1,268 @@
{
"Organization": "env(ORGANIZATION_NAME)",
"DeploymentName": "ntier-iaas",
"InstanceName": "${Parameters.Organization}-${Parameters.DeploymentName}",
"Subscription": "NTier_IaaS",
"ModuleConfigurationParameters": {
"DeploymentUserId": "env(DEPLOYMENT_USER_ID)",
"OnPremisesInformation": {
"ActiveDirectory": {
"PrimaryDomainControllerIP": "192.168.1.4",
"DomainName": "fontoso.com",
"ADSitename": "Cloud-Site",
"DomainAdminUserName": "fontoso"
},
"Network": {
"AddressPrefix": "192.168.1.0/28"
}
},
"Comments": "Adding VirtualNetwork property, because KeyVault references a VirtualNetwork property references NetworkSecurityGroups and RouteTable, this is why these two properties are also included",
"RouteTables": "file(../LandingZone/NetworkParameters/routeTables.json)",
"NetworkSecurityGroups": "file(../LandingZone/NetworkParameters/networkSecurityGroups.json)",
"VirtualNetwork": "file(../LandingZone/NetworkParameters/virtualNetwork.json)",
"KeyVault": {
"Name": "${Parameters.InstanceName}-kv",
"ResourceGroup": "${Parameters.InstanceName}-keyvault-rg",
"Sku": "Premium",
"EnableVaultForDeployment": true,
"EnableVaultForDiskEncryption": true,
"EnableVaultForTemplateDeployment": true,
"AccessPolicies": [
{
"tenantId": "${Parameters.TenantId}",
"objectId": "${Parameters.ModuleConfigurationParameters.DeploymentUserId}",
"permissions": {
"certificates": [
"All"
],
"keys": [
"All"
],
"secrets": [
"All"
]
}
}
],
"SecretsObject": {
"Comments": "Creating an object so we can use a secretsobject parameter type in our ARM template",
"Secrets": [
{
"secretName": "admin-user",
"secretValue": "env(ADMIN_USER_PWD)"
}
]
},
"NetworkAcls": {
"bypass": "AzureServices",
"defaultAction": "Deny",
"virtualNetworkRules": [
{
"subnet": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.Subnets[0].Name}"
}
],
"ipRules": []
}
},
"WebApp": {
"Name": "web-vmss",
"ResourceGroup": "${Parameters.InstanceName}-webapp-rg",
"VMSKU": {
"name": "Standard_DS3_v2",
"tier": "Standard",
"capacity": 5
},
"OSImage": {
"offer": "WindowsServer",
"publisher": "MicrosoftWindowsServer",
"sku": "2016-Datacenter"
},
"OSType": "Windows",
"Kek": {
"Name": "WebAppKey",
"Comments": "Destination can be HSM or Software. Use HSM to create Production keys.",
"Destination": "HSM"
},
"DomainName": "${Parameters.ModuleConfigurationParameters.ActiveDirectory.DomainName}",
"DomainAdminUsername": "env(DOMAIN_ADMIN_USERNAME)",
"DomainAdminPassword": "env(DOMAIN_ADMIN_USER_PWD)",
"AdminUsername": "${Parameters.ModuleConfigurationParameters.KeyVault.SecretsObject.Secrets[0].secretName}",
"AdminPassword": {
"keyVault": {
"id": "reference(KeyVault.keyVaultResourceId)"
},
"secretName": "${Parameters.ModuleConfigurationParameters.KeyVault.SecretsObject.Secrets[0].secretName}"
},
"SubnetName": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.Subnets[0].name}"
},
"WebAppLoadBalancer": {
"Name": "web-lb",
"ResourceGroup": "${Parameters.ModuleConfigurationParameters.WebApp.ResourceGroup}",
"LoadBalancingRules": [
{
"name": "LBRule",
"properties": {
"frontendPort": 80,
"backendPort": 80,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 3,
"protocol": "TCP",
"enableTcpReset": false,
"loadDistribution": false,
"disableOutboundSnat": false,
"probeName": "tcpProbe"
}
}
],
"Probes": [
{
"name": "probe",
"properties": {
"protocol": "TCP",
"port": 80,
"requestPath": "/",
"intervalInSeconds": 10,
"numberOfProbes": 5
}
}
],
"SubnetName": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.Subnets[0].name}"
},
"BusinessApp": {
"Name": "biz-vmss",
"ResourceGroup": "${Parameters.InstanceName}-biz-rg",
"VMSKU": {
"name": "Standard_DS3_v2",
"tier": "Standard",
"capacity": 5
},
"OSImage": {
"offer": "WindowsServer",
"publisher": "MicrosoftWindowsServer",
"sku": "2016-Datacenter"
},
"OSType": "Windows",
"Kek": {
"Name": "WebAppKey",
"Comments": "Destination can be HSM or Software. Use HSM to create Production keys.",
"Destination": "HSM"
},
"SubnetName": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.Subnets[0].name}"
},
"BusinessAppLoadBalancer": {
"Name": "${Parameters.InstanceName}-biz-lb",
"ResourceGroup": "${Parameters.ModuleConfigurationParameters.BusinessApp.ResourceGroup}",
"LoadBalancingRules": [
{
"name": "LBRule",
"properties": {
"frontendPort": 80,
"backendPort": 80,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 3,
"protocol": "TCP",
"enableTcpReset": false,
"loadDistribution": false,
"disableOutboundSnat": false,
"probeName": "tcpProbe"
}
}
],
"Probes": [
{
"name": "probe",
"properties": {
"protocol": "TCP",
"port": 80,
"requestPath": "/",
"intervalInSeconds": 10,
"numberOfProbes": 5
}
}
],
"SubnetName": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.Subnets[0].name}"
},
"SQLServerAlwaysOn": {
"Name": "sql-vm",
"ResourceGroup": "${Parameters.InstanceName}-data-rg",
"VMCount": 2,
"VMSize": "Standard_DS14_v2",
"OSType": "Windows",
"OSImage": {
"offer": "SQL2017-WS2016",
"publisher": "MicrosoftSQLServer",
"sku": "Enterprise"
},
"IPAddressStart": "172.2.0.20",
"DomainName": "${Parameters.ModuleConfigurationParameters.ActiveDirectory.DomainName}",
"DomainAdminUsername": "env(DOMAIN_ADMIN_USERNAME)",
"DomainAdminPassword": "env(DOMAIN_ADMIN_USER_PWD)",
"AdminUsername": "${Parameters.ModuleConfigurationParameters.KeyVault.SecretsObject.Secrets[0].secretName}",
"AdminPassword": {
"keyVault": {
"id": "reference(KeyVault.keyVaultResourceId)"
},
"secretName": "${Parameters.ModuleConfigurationParameters.KeyVault.SecretsObject.Secrets[0].secretName}"
},
"DataDisks": [
{
"size": 1023
},
{
"size": 1023
}
]
},
"SQLServerAlwaysOnCloudWitness": {
"Name": "${Parameters.InstanceName}cwntierstrg",
"ResourceGroup": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.ResourceGroup}",
"Sku": "Standard_GRS",
"NetworkAcls": {
"bypass": "AzureServices",
"defaultAction": "Deny",
"virtualNetworkRules": [
{
"subnet": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.Subnets[0].Name}"
}
],
"ipRules": []
},
"Policies": {
"Effect": "Audit"
}
},
"SQLServerAlwaysOnLoadBalancer": {
"Name": "${Parameters.InstanceName}-data-lb",
"ResourceGroup": "${Parameters.ModuleConfigurationParameters.SQLServerAlwaysOn.ResourceGroup}",
"IPAddressStart": "172.2.0.22",
"LoadBalancingRules": [
{
"name": "LBRule",
"properties": {
"frontendPort": 1433,
"backendPort": 1433,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 5,
"protocol": "TCP",
"enableTcpReset": false,
"loadDistribution": false,
"disableOutboundSnat": false,
"probeName": "tcpProbe"
}
}
],
"Probes": [
{
"name": "probe",
"properties": {
"protocol": "TCP",
"port": 1433,
"intervalInSeconds": 5,
"numberOfProbes": 2
}
}
],
"SubnetName": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.Subnets[0].name}"
}
}
}

Просмотреть файл

@ -0,0 +1,336 @@
variables:
- group: VDC_SECRETS
trigger:
- master
stages:
- stage: Validate
jobs:
- job: SetupValidationResourceGroup
pool:
name: 'vdc-self-hosted'
steps:
- task: AzurePowerShell@4
displayName: "Setup Validation Resource Group"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ValidationResourceGroupSetup.ps1'
ScriptArguments: '-ResourceGroupName vdc-validation-rg -SetupResourceGroup'
azurePowerShellVersion: 'LatestVersion'
- job: KeyVault
pool:
name: 'vdc-self-hosted'
dependsOn: SetupValidationResourceGroup
steps:
- task: PowerShell@2
displayName: "Pester Tests for Module - Key Vault"
inputs:
targetType: 'inline'
script: '# Write your powershell commands here.
Invoke-Pester -Script "./Modules/KeyVault/2.0/Tests";
# Use the environment variables input below to pass secret variables to this script.'
pwsh: true
- task: AzurePowerShell@4
displayName: "ARM Validation - Key Vault"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/Archetype/definition.json" -ModuleConfigurationName "KeyVault" -Validate'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: AppServiceEnvironments
pool:
name: 'vdc-self-hosted'
dependsOn: SetupValidationResourceGroup
steps:
- task: PowerShell@2
displayName: "Pester Tests for Module - App Service Environments"
inputs:
targetType: 'inline'
script: '# Write your powershell commands here.
Invoke-Pester -Script "./Modules/AppServiceEnvironments/2.0/Tests";
# Use the environment variables input below to pass secret variables to this script.'
pwsh: true
- task: AzurePowerShell@4
displayName: "ARM Validation - App Service Environments"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/Archetype/definition.json" -ModuleConfigurationName "AppServiceEnvironments" -Validate'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: AppServicePlan
pool:
name: 'vdc-self-hosted'
dependsOn: SetupValidationResourceGroup
steps:
- task: PowerShell@2
displayName: "Pester Tests for Module - App Service Plan"
inputs:
targetType: 'inline'
script: '# Write your powershell commands here.
Invoke-Pester -Script "./Modules/AppServicePlan/2.0/Tests";
# Use the environment variables input below to pass secret variables to this script.'
pwsh: true
- task: AzurePowerShell@4
displayName: "ARM Validation - App Service Plan"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/Archetype/definition.json" -ModuleConfigurationName "AppServicePlan" -Validate'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: AppServiceWebApp
pool:
name: 'vdc-self-hosted'
dependsOn: SetupValidationResourceGroup
steps:
- task: PowerShell@2
displayName: "Pester Tests for Module - App Service WebApp"
inputs:
targetType: 'inline'
script: '# Write your powershell commands here.
Invoke-Pester -Script "./Modules/AppServiceWebApp/2.0/Tests";
# Use the environment variables input below to pass secret variables to this script.'
pwsh: true
- task: AzurePowerShell@4
displayName: "ARM Validation - App Service WebApp"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/Archetype/definition.json" -ModuleConfigurationName "AppServiceWebApp" -Validate'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: SQLDBServer
pool:
name: 'vdc-self-hosted'
dependsOn: SetupValidationResourceGroup
steps:
- task: PowerShell@2
displayName: "Pester Tests for Module - SQLDB Server"
inputs:
targetType: 'inline'
script: '# Write your powershell commands here.
Invoke-Pester -Script "./Modules/SQLDBServer/2.0/Tests";
# Use the environment variables input below to pass secret variables to this script.'
pwsh: true
- task: AzurePowerShell@4
displayName: "ARM Validation - SQLDB Server"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/Archetype/definition.json" -ModuleConfigurationName "SQLDBServer" -Validate'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: SQLDatabase
pool:
name: 'vdc-self-hosted'
dependsOn: SetupValidationResourceGroup
steps:
- task: PowerShell@2
displayName: "Pester Tests for Module - SQL Database"
inputs:
targetType: 'inline'
script: '# Write your powershell commands here.
Invoke-Pester -Script "./Modules/SQLDatabase/2.0/Tests";
# Use the environment variables input below to pass secret variables to this script.'
pwsh: true
- task: AzurePowerShell@4
displayName: "ARM Validation - SQL Database"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/Archetype/definition.json" -ModuleConfigurationName "SQLDatabase" -Validate'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: TearDownValidationResourceGroup
pool:
name: 'vdc-self-hosted'
dependsOn: [ KeyVault, AppServiceEnvironments, AppServicePlan, AppServiceWebApp, SQLDBServer, SQLDatabase ]
steps:
- task: AzurePowerShell@4
displayName: "Teardown Validation Resource Group"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ValidationResourceGroupSetup.ps1'
ScriptArguments: '-TearDownResourceGroup'
azurePowerShellVersion: 'LatestVersion'
- stage: Deploy
jobs:
- job: KeyVault
pool:
name: 'vdc-self-hosted'
steps:
- task: AzurePowerShell@4
displayName: "Key Vault"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/Archetype/definition.json" -ModuleConfigurationName "KeyVault"'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_SUBSCRIPTIONS:VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: AppServiceEnvironments
timeoutInMinutes: 0
pool:
name: 'vdc-self-hosted'
steps:
- task: AzurePowerShell@4
displayName: "App Service Environments"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/Archetype/definition.json" -ModuleConfigurationName "AppServiceEnvironments"'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_SUBSCRIPTIONS:VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: AppServicePlan
timeoutInMinutes: 0
pool:
name: 'vdc-self-hosted'
dependsOn: AppServiceEnvironments
steps:
- task: AzurePowerShell@4
displayName: "App Service Plan"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/Archetype/definition.json" -ModuleConfigurationName "AppServicePlan"'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_SUBSCRIPTIONS:VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: AppServiceWebApp
pool:
name: 'vdc-self-hosted'
dependsOn: AppServicePlan
steps:
- task: AzurePowerShell@4
displayName: "App Service WebApp"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/Archetype/definition.json" -ModuleConfigurationName "AppServiceWebApp"'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_SUBSCRIPTIONS:VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: SQLDBServer
timeoutInMinutes: 0
pool:
name: 'vdc-self-hosted'
dependsOn: KeyVault
steps:
- task: AzurePowerShell@4
displayName: "SQLDB Server"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/Archetype/definition.json" -ModuleConfigurationName "SQLDBServer"'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_SUBSCRIPTIONS:VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: SQLDatabase
timeoutInMinutes: 0
pool:
name: 'vdc-self-hosted'
dependsOn: SQLDBServer
steps:
- task: AzurePowerShell@4
displayName: "SQLDatabase"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/Archetype/definition.json" -ModuleConfigurationName "SQLDatabase"'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_SUBSCRIPTIONS:VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)

Просмотреть файл

@ -0,0 +1,12 @@
{
"ResourceGroup": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.ResourceGroup}",
"Web": {
"Name": "web-asg"
},
"Business": {
"Name": "business-asg"
},
"Data": {
"Name": "data-asg"
}
}

Просмотреть файл

@ -0,0 +1,178 @@
{
"ResourceGroup": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.ResourceGroup}",
"Default": {
"Name": "default-nsg",
"Rules": [
{
"name": "allow-azure-loadbalancer",
"properties": {
"access": "Allow",
"destinationAddressPrefixes": [],
"destinationAddressPrefix": "VirtualNetwork",
"destinationPortRange": "*",
"destinationPortRanges": [],
"destinationApplicationSecurityGroups": [],
"direction": "Inbound",
"priority": 100,
"protocol": "*",
"sourcePortRange": "*",
"sourcePortRanges": [],
"sourceAddressPrefix": "AzureLoadBalancer",
"sourceApplicationSecurityGroups": []
}
},
{
"name": "allow-vnet-to-web",
"properties": {
"access": "Allow",
"destinationAddressPrefixes": [],
"destinationAddressPrefix": "",
"destinationPortRange": "",
"destinationPortRanges": [
"80",
"443"
],
"destinationApplicationSecurityGroups": [
{
"name": "${Parameters.ModuleConfigurationParameters.ApplicationSecurityGroups.Web.Name}"
}
],
"direction": "Inbound",
"priority": 110,
"protocol": "*",
"sourcePortRange": "*",
"sourcePortRanges": [],
"sourceAddressPrefix": "VirtualNetwork",
"sourceApplicationSecurityGroups": []
}
},
{
"name": "allow-web-to-business",
"properties": {
"access": "Allow",
"destinationAddressPrefixes": [],
"destinationAddressPrefix": "",
"destinationPortRange": "",
"destinationPortRanges": [
"80",
"443"
],
"destinationApplicationSecurityGroups": [
{
"name": "${Parameters.ModuleConfigurationParameters.ApplicationSecurityGroups.Business.Name}"
}
],
"direction": "Inbound",
"priority": 120,
"protocol": "*",
"sourcePortRange": "*",
"sourcePortRanges": [],
"sourceAddressPrefix": "",
"sourceApplicationSecurityGroups": [
{
"name": "${Parameters.ModuleConfigurationParameters.ApplicationSecurityGroups.Web.Name}"
}
]
}
},
{
"name": "allow-business-to-data",
"properties": {
"access": "Allow",
"destinationAddressPrefixes": [],
"destinationAddressPrefix": "",
"destinationPortRange": "1433",
"destinationPortRanges": [],
"destinationApplicationSecurityGroups": [
{
"name": "${Parameters.ModuleConfigurationParameters.ApplicationSecurityGroups.Data.Name}"
}
],
"direction": "Inbound",
"priority": 130,
"protocol": "*",
"sourcePortRange": "*",
"sourcePortRanges": [],
"sourceAddressPrefix": "",
"sourceApplicationSecurityGroups": [
{
"name": "${Parameters.ModuleConfigurationParameters.ApplicationSecurityGroups.Business.Name}"
}
]
}
},
{
"name": "allow-rdp",
"properties": {
"access": "Allow",
"destinationAddressPrefixes": [],
"destinationAddressPrefix": "VirtualNetwork",
"destinationPortRange": "3389",
"destinationPortRanges": [],
"destinationApplicationSecurityGroups": [],
"direction": "Inbound",
"priority": 200,
"protocol": "Tcp",
"sourcePortRange": "*",
"sourcePortRanges": [],
"sourceAddressPrefix": "${Parameters.ModuleConfigurationParameters.SharedServices.Jumpbox_SubnetAddressPrefix}",
"sourceApplicationSecurityGroups": []
}
},
{
"name": "allow-ssh",
"properties": {
"access": "Allow",
"destinationAddressPrefixes": [],
"destinationAddressPrefix": "VirtualNetwork",
"destinationPortRange": "22",
"destinationPortRanges": [],
"destinationApplicationSecurityGroups": [],
"direction": "Inbound",
"priority": 210,
"protocol": "Tcp",
"sourcePortRange": "*",
"sourcePortRanges": [],
"sourceAddressPrefix": "${Parameters.ModuleConfigurationParameters.SharedServices.Jumpbox_SubnetAddressPrefix}",
"sourceApplicationSecurityGroups": []
}
},
{
"name": "deny-internet",
"properties": {
"access": "Deny",
"destinationAddressPrefixes": [],
"destinationAddressPrefix": "*",
"destinationPortRange": "*",
"destinationPortRanges": [],
"destinationApplicationSecurityGroups": [],
"direction": "Inbound",
"priority": 4095,
"protocol": "Tcp",
"sourcePortRange": "*",
"sourcePortRanges": [],
"sourceAddressPrefix": "Internet",
"sourceApplicationSecurityGroups": []
}
},
{
"name": "deny-vnet",
"properties": {
"access": "Deny",
"destinationAddressPrefixes": [],
"destinationAddressPrefix": "VirtualNetwork",
"destinationPortRange": "*",
"destinationPortRanges": [],
"destinationApplicationSecurityGroups": [],
"direction": "Inbound",
"priority": 4096,
"protocol": "Tcp",
"sourcePortRange": "*",
"sourcePortRanges": [],
"sourceAddressPrefix": "VirtualNetwork",
"sourceApplicationSecurityGroups": []
}
}
]
}
}

Просмотреть файл

@ -0,0 +1,23 @@
{
"ResourceGroup": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.ResourceGroup}",
"Default": {
"Name": "default-udr",
"Routes": [
{
"name": "default",
"properties": {
"addressPrefix": "0.0.0.0/0",
"nextHopIpAddress": "reference(${Parameters.Organization}-shrdsvcs.AzureFirewall.azureFirewallPrivateIp)",
"nextHopType": "VirtualAppliance"
}
},
{
"name": "to-on-premises",
"properties": {
"addressPrefix": "${Parameters.ModuleConfigurationParameters.OnPremisesInformation.Network.AddressPrefix}",
"nextHopType": "VirtualNetworkGateway"
}
}
]
}
}

Просмотреть файл

@ -0,0 +1,30 @@
{
"Name": "${Parameters.InstanceName}-vnet",
"ResourceGroup": "${Parameters.InstanceName}-network-rg",
"AddressPrefixes": [
"172.2.0.0/16"
],
"EnableDdosProtection": false,
"Subnets": [
{
"name": "default",
"addressPrefix": "172.2.0.0/24",
"networkSecurityGroupName": "${Parameters.ModuleConfigurationParameters.NetworkSecurityGroups.Default.Name}",
"routeTableName": "${Parameters.ModuleConfigurationParameters.RouteTables.Default.Name}",
"serviceEndpoints": [{
"service": "Microsoft.EventHub"
},
{
"service": "Microsoft.Sql"
},
{
"service": "Microsoft.Storage"
},
{
"service": "Microsoft.KeyVault"
}
]
}
],
"DnsServers": "reference(${Parameters.Organization}-shrdsvcs.InstallActiveDirectoryDomainServices.dnsServers)"
}

Просмотреть файл

@ -0,0 +1,5 @@
{
"Subscriptions": "env(VDC_SUBSCRIPTIONS)",
"Parameters": "file(./parameters.json)",
"Orchestration": "file(./orchestration.json)"
}

Просмотреть файл

@ -0,0 +1,273 @@
{
"ModuleConfigurationsPath": "../../../Modules",
"ModuleConfigurations": [
{
"Name": "SubscriptionCreation",
"Enabled": false,
"Script": {
"Command": "../../../Scripts/Subscription/NewSubscription.ps1",
"Arguments": {
"SubscriptionName": "vdc2-nist-workload10",
"Location": "West US 2",
"TenantId": "env(TENANT_ID)",
"OfferType": "MS-AZR-0017P"
},
"UpdatePath": "Subscriptions.ASE_SQLDB"
}
},
{
"Name": "DiagnosticStorageAccount",
"ModuleDefinitionName": "StorageAccounts",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.DiagnosticStorageAccount.ResourceGroup}",
"Comments": "Storage Account that is used to store Diagnostic information of VMs and Non-VM resources",
"Version": "2.0",
"Policies": {
"Comments": "Policies is Optional - If no object is specified, no Policies deployment will occur",
"OverrideParameters": {
"effect": {
"value": "${Parameters.ModuleConfigurationParameters.DiagnosticStorageAccount.Policies.Effect}"
},
"resourceGroup": {
"value": "${Parameters.ModuleConfigurationParameters.DiagnosticStorageAccount.ResourceGroup}"
},
"resourceGroupLocation": {
"value": "${Parameters.Location}"
}
}
},
"Deployment": {
"Comments": "We need the 'update' module instance to lock this resource after the Virtual Network got created",
"TemplatePath": "../../../Modules/StorageAccounts/2.0/deploy.json",
"OverrideParameters": {
"storageAccountName": {
"value": "${Parameters.ModuleConfigurationParameters.DiagnosticStorageAccount.Name}"
},
"storageAccountSku": {
"value": "${Parameters.ModuleConfigurationParameters.DiagnosticStorageAccount.Sku}"
}
}
}
},
{
"Name": "LogAnalytics",
"ModuleDefinitionName": "LogAnalytics",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.LogAnalytics.ResourceGroup}",
"DependsOn": [
"DiagnosticStorageAccount"
],
"Deployment": {
"OverrideParameters": {
"logAnalyticsWorkspaceName": {
"value": "${Parameters.ModuleConfigurationParameters.LogAnalytics.Name}"
},
"diagnosticStorageAccountName": {
"value": "reference(DiagnosticStorageAccount.storageAccountName)"
},
"diagnosticStorageAccountId": {
"value": "reference(DiagnosticStorageAccount.storageAccountResourceId)"
},
"diagnosticStorageAccountAccessKey": {
"value": "reference(DiagnosticStorageAccount.storageAccountAccessKey)"
},
"location": {
"value": "${Parameters.ModuleConfigurationParameters.LogAnalytics.Location}"
}
}
}
},
{
"Name": "AzureSecurityCenter",
"ModuleDefinitionName": "AzureSecurityCenter",
"DependsOn": [
"LogAnalytics"
],
"Deployment": {
"OverrideParameters": {
"workspaceId": {
"value": "reference(LogAnalytics.logAnalyticsWorkspaceResourceId)"
}
}
}
},
{
"Name": "NISTControls",
"ModuleDefinitionName": "NISTControls",
"DependsOn": [
"LogAnalytics"
],
"Deployment": {
"OverrideParameters": {
"workspaceId": {
"value": "reference(LogAnalytics.logAnalyticsWorkspaceId)"
},
"location": {
"value": "${Parameters.Location}"
}
}
}
},
{
"Name": "WebASG",
"ModuleDefinitionName": "ApplicationSecurityGroups",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.ApplicationSecurityGroups.ResourceGroup}",
"DependsOn": [],
"Deployment": {
"OverrideParameters": {
"applicationSecurityGroupName": {
"value": "${Parameters.ModuleConfigurationParameters.ApplicationSecurityGroups.Web.Name}"
}
}
}
},
{
"Name": "BusinessASG",
"ModuleDefinitionName": "ApplicationSecurityGroups",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.ApplicationSecurityGroups.ResourceGroup}",
"DependsOn": [],
"Deployment": {
"OverrideParameters": {
"applicationSecurityGroupName": {
"value": "${Parameters.ModuleConfigurationParameters.ApplicationSecurityGroups.Business.Name}"
}
}
}
},
{
"Name": "DataASG",
"ModuleDefinitionName": "ApplicationSecurityGroups",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.ApplicationSecurityGroups.ResourceGroup}",
"DependsOn": [],
"Deployment": {
"OverrideParameters": {
"applicationSecurityGroupName": {
"value": "${Parameters.ModuleConfigurationParameters.ApplicationSecurityGroups.Data.Name}"
}
}
}
},
{
"Name": "DefaultNSG",
"ModuleDefinitionName": "NetworkSecurityGroups",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.NetworkSecurityGroups.ResourceGroup}",
"DependsOn": [
"WebASG",
"BusinessASG",
"DataASG",
"DiagnosticStorageAccount",
"LogAnalytics"
],
"Deployment": {
"OverrideParameters": {
"workspaceId": {
"value": "reference(LogAnalytics.logAnalyticsWorkspaceResourceId)"
},
"diagnosticStorageAccountId": {
"value": "reference(DiagnosticStorageAccount.storageAccountResourceId)"
},
"networkSecurityGroupName": {
"value": "${Parameters.ModuleConfigurationParameters.NetworkSecurityGroups.Default.Name}"
},
"networkSecurityGroupSecurityRules": {
"value": "${Parameters.ModuleConfigurationParameters.NetworkSecurityGroups.Default.Rules}"
}
}
}
},
{
"Name": "DefaultRouteTable",
"ModuleDefinitionName": "RouteTables",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.RouteTables.ResourceGroup}",
"DependsOn": [],
"Deployment": {
"OverrideParameters": {
"routeTableName": {
"value": "${Parameters.ModuleConfigurationParameters.RouteTables.Default.Name}"
},
"routes": {
"value": "${Parameters.ModuleConfigurationParameters.RouteTables.Default.Routes}"
}
}
}
},
{
"Name": "VirtualNetwork",
"ModuleDefinitionName": "VirtualNetwork",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.ResourceGroup}",
"DependsOn": [
"DefaultNSG",
"DefaultRouteTable"
],
"Deployment": {
"OverrideParameters": {
"vnetName": {
"value": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.Name}"
},
"vnetAddressPrefixes": {
"value": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.AddressPrefixes}"
},
"dnsServers": {
"value": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.DnsServers}"
},
"subnets": {
"value": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.Subnets}"
},
"enableDdosProtection": {
"value": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.EnableDdosProtection}"
},
"enableVmProtection": {
"value": false
}
}
}
},
{
"Name": "LocalVirtualNetworkPeering",
"ModuleDefinitionName": "VirtualNetworkPeering",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.ResourceGroup}",
"DependsOn": [
"VirtualNetwork"
],
"Deployment": {
"OverrideParameters": {
"localVnetName": {
"value": "reference(VirtualNetwork.vNetName)"
},
"peeringName": {
"value": "${Parameters.ModuleConfigurationParameters.VirtualNetworkPeering.LocalPeering.Name}"
},
"remoteVirtualNetworkId": {
"value": "reference(${Parameters.Organization}-shrdsvcs.VirtualNetwork.vNetResourceId)"
}
}
}
},
{
"Name": "RemoteVirtualNetworkPeering",
"ModuleDefinitionName": "VirtualNetworkPeering",
"Subscription": "SharedServices",
"ResourceGroupName": "reference(${Parameters.Organization}-shrdsvcs.VirtualNetwork.vNetResourceGroup)",
"DependsOn": [
"VirtualNetwork"
],
"Deployment": {
"OverrideParameters": {
"localVnetName": {
"value": "reference(${Parameters.Organization}-shrdsvcs.VirtualNetwork.vNetName)"
},
"peeringName": {
"value": "${Parameters.ModuleConfigurationParameters.VirtualNetworkPeering.RemotePeering.Name}"
},
"remoteVirtualNetworkId": {
"value": "reference(${Parameters.InstanceName}.VirtualNetwork.vNetResourceId)"
},
"allowGatewayTransit": {
"value": "${Parameters.ModuleConfigurationParameters.VirtualNetworkPeering.RemotePeering.AllowGatewayTransit}"
},
"useRemoteGateways": {
"value": "${Parameters.ModuleConfigurationParameters.VirtualNetworkPeering.RemotePeering.UseRemoteGateways}"
}
}
}
}
]
}

Просмотреть файл

@ -0,0 +1,51 @@
{
"Organization": "env(ORGANIZATION_NAME)",
"DeploymentName": "ntier-iaas",
"InstanceName": "${Parameters.Organization}-${Parameters.DeploymentName}",
"Subscription": "NTier_IaaS",
"ModuleConfigurationParameters": {
"OnPremisesInformation": {
"Network": {
"AddressPrefix": "192.168.1.0/28"
}
},
"SharedServices": {
"Jumpbox_SubnetAddressPrefix": "172.0.0.0/24"
},
"DiagnosticStorageAccount": {
"Name": "${Parameters.Organization}asesqldiag01",
"ResourceGroup": "${Parameters.InstanceName}-diagnostics-rg",
"Sku": "Standard_GRS",
"NetworkAcls": {
"bypass": "AzureServices",
"defaultAction": "Deny",
"virtualNetworkRules": [{
"subnet": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.Subnets[0].Name}"
}],
"ipRules": []
},
"Policies": {
"Effect": "Audit"
}
},
"LogAnalytics": {
"Name": "${Parameters.InstanceName}-la",
"ResourceGroup": "${Parameters.InstanceName}-diagnostics-rg",
"Location": "${Parameters.Location}"
},
"ApplicationSecurityGroups": "file(NetworkParameters/applicationSecurityGroups.json)",
"NetworkSecurityGroups": "file(NetworkParameters/networkSecurityGroups.json)",
"RouteTables": "file(NetworkParameters/routeTables.json)",
"VirtualNetwork": "file(NetworkParameters/virtualNetwork.json)",
"VirtualNetworkPeering": {
"LocalPeering": {
"Name": "${Parameters.DeploymentName}-to-sharedsvcs"
},
"RemotePeering": {
"Name": "sharedsvcs-to-${Parameters.DeploymentName}",
"AllowGatewayTransit": true,
"UseRemoteGateways": false
}
}
}
}

Просмотреть файл

@ -0,0 +1,452 @@
variables:
- group: VDC_SECRETS
trigger:
- master
stages:
- stage: Validate
jobs:
- job: SetupValidationResourceGroup
pool:
name: 'vdc-self-hosted'
steps:
- task: AzurePowerShell@4
displayName: "Setup Validation Resource Group"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ValidationResourceGroupSetup.ps1'
ScriptArguments: '-ResourceGroupName vdc-validation-rg -SetupResourceGroup'
azurePowerShellVersion: 'LatestVersion'
- job: StorageAccounts
pool:
name: 'vdc-self-hosted'
dependsOn: SetupValidationResourceGroup
steps:
- task: PowerShell@2
displayName: "Pester Tests for Module - Storage Accounts"
inputs:
targetType: 'inline'
script: '# Write your powershell commands here.
Invoke-Pester -Script "./Modules/StorageAccounts/2.0/Tests";
# Use the environment variables input below to pass secret variables to this script.'
pwsh: true
- task: AzurePowerShell@4
displayName: "ARM Validation - Diagnostic Storage Account"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/LandingZone/definition.json" -ModuleConfigurationName "DiagnosticStorageAccount" -Validate'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: LogAnalytics
pool:
name: 'vdc-self-hosted'
dependsOn: SetupValidationResourceGroup
steps:
- task: PowerShell@2
displayName: "Pester Tests for Module - Log Analytics"
inputs:
targetType: 'inline'
script: '# Write your powershell commands here.
Invoke-Pester -Script "./Modules/LogAnalytics/2.0/Tests";
# Use the environment variables input below to pass secret variables to this script.'
pwsh: true
- task: AzurePowerShell@4
displayName: "ARM Validation - Log Analytics"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/LandingZone/definition.json" -ModuleConfigurationName "LogAnalytics" -Validate'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: AzureSecurityCenter
pool:
name: 'vdc-self-hosted'
dependsOn: SetupValidationResourceGroup
steps:
- task: PowerShell@2
displayName: "Pester Tests for Module - Azure Security Center"
inputs:
targetType: 'inline'
script: '# Write your powershell commands here.
Invoke-Pester -Script "./Modules/AzureSecurityCenter/2.0/Tests";
# Use the environment variables input below to pass secret variables to this script.'
pwsh: true
- task: AzurePowerShell@4
displayName: "ARM Validation - Azure Security Center"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/LandingZone/definition.json" -ModuleConfigurationName "AzureSecurityCenter" -Validate'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: NISTControls
pool:
name: 'vdc-self-hosted'
dependsOn: SetupValidationResourceGroup
steps:
- task: PowerShell@2
displayName: "Pester Tests for Module - NIST Controls"
inputs:
targetType: 'inline'
script: '# Write your powershell commands here.
Invoke-Pester -Script "./Modules/NISTControls/2.0/Tests";
# Use the environment variables input below to pass secret variables to this script.'
pwsh: true
- task: AzurePowerShell@4
displayName: "ARM Validation - NIST Controls"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/LandingZone/definition.json" -ModuleConfigurationName "NISTControls" -Validate'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: NetworkSecurityGroups
pool:
name: 'vdc-self-hosted'
dependsOn: SetupValidationResourceGroup
steps:
- task: PowerShell@2
displayName: "Pester Tests for Module - Network Security Groups"
inputs:
targetType: 'inline'
script: '# Write your powershell commands here.
Invoke-Pester -Script "./Modules/NetworkSecurityGroups/2.0/Tests";
# Use the environment variables input below to pass secret variables to this script.'
pwsh: true
- task: AzurePowerShell@4
displayName: "ARM Validation - Default NSG"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/LandingZone/definition.json" -ModuleConfigurationName "DefaultNSG" -Validate'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: RouteTables
pool:
name: 'vdc-self-hosted'
dependsOn: SetupValidationResourceGroup
steps:
- task: PowerShell@2
displayName: "Pester Tests for Module - Route Tables"
inputs:
targetType: 'inline'
script: '# Write your powershell commands here.
Invoke-Pester -Script "./Modules/RouteTables/2.0/Tests";
# Use the environment variables input below to pass secret variables to this script.'
pwsh: true
- task: AzurePowerShell@4
displayName: "ARM Validation - Default Route Table"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/LandingZone/definition.json" -ModuleConfigurationName "DefaultRouteTable" -Validate'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: vNet
pool:
name: 'vdc-self-hosted'
dependsOn: SetupValidationResourceGroup
steps:
- task: PowerShell@2
displayName: "Pester Tests for Module - vNet"
inputs:
targetType: 'inline'
script: '# Write your powershell commands here.
Invoke-Pester -Script "./Modules/vNet/2.0/Tests";
# Use the environment variables input below to pass secret variables to this script.'
pwsh: true
- task: AzurePowerShell@4
displayName: "ARM Validation - Virtual Network"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/LandingZone/definition.json" -ModuleConfigurationName "VirtualNetwork" -Validate'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: VirtualNetworkPeering
pool:
name: 'vdc-self-hosted'
dependsOn: SetupValidationResourceGroup
steps:
- task: PowerShell@2
displayName: "Pester Tests for Module - vNet Peering"
inputs:
targetType: 'inline'
script: '# Write your powershell commands here.
Invoke-Pester -Script "./Modules/vNetPeering/2.0/Tests";
# Use the environment variables input below to pass secret variables to this script.'
pwsh: true
- task: AzurePowerShell@4
displayName: "ARM Validation - Local Virtual Network Peering"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/LandingZone/definition.json" -ModuleConfigurationName "LocalVirtualNetworkPeering" -Validate'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: TearDownValidationResourceGroup
pool:
name: 'vdc-self-hosted'
dependsOn: [ StorageAccounts, LogAnalytics, AzureSecurityCenter, NISTControls, NetworkSecurityGroups, RouteTables, vNet, VirtualNetworkPeering ]
steps:
- task: AzurePowerShell@4
displayName: "Teardown Validation Resource Group"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ValidationResourceGroupSetup.ps1'
ScriptArguments: '-TearDownResourceGroup'
azurePowerShellVersion: 'LatestVersion'
- stage: Deploy
jobs:
- job: DiagnosticStorageAccount
pool:
name: 'vdc-self-hosted'
steps:
- task: AzurePowerShell@4
displayName: "Diagnostic Storage Account"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/LandingZone/definition.json" -ModuleConfigurationName "DiagnosticStorageAccount"'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_SUBSCRIPTIONS:VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: LogAnalytics
pool:
name: 'vdc-self-hosted'
dependsOn: DiagnosticStorageAccount
steps:
- task: AzurePowerShell@4
displayName: "Log Analytics"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/LandingZone/definition.json" -ModuleConfigurationName "LogAnalytics"'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_SUBSCRIPTIONS:VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: AzureSecurityCenter
pool:
name: 'vdc-self-hosted'
dependsOn: LogAnalytics
steps:
- task: AzurePowerShell@4
displayName: "Azure Security Center"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/LandingZone/definition.json" -ModuleConfigurationName "AzureSecurityCenter"'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_SUBSCRIPTIONS:VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: NISTControls
pool:
name: 'vdc-self-hosted'
dependsOn: LogAnalytics
steps:
- task: AzurePowerShell@4
displayName: "NIST Controls"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/LandingZone/definition.json" -ModuleConfigurationName "NISTControls"'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_SUBSCRIPTIONS:VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: DefaultNetworkSecurityGroup
pool:
name: 'vdc-self-hosted'
dependsOn: [ DiagnosticStorageAccount, LogAnalytics ]
steps:
- task: AzurePowerShell@4
displayName: "Default Network Security Group"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/LandingZone/definition.json" -ModuleConfigurationName "DefaultNSG"'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_SUBSCRIPTIONS:VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: DefaultRouteTable
pool:
name: 'vdc-self-hosted'
steps:
- task: AzurePowerShell@4
displayName: "Default Route Table"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/LandingZone/definition.json" -ModuleConfigurationName "DefaultRouteTable"'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_SUBSCRIPTIONS:VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: VirtualNetwork
pool:
name: 'vdc-self-hosted'
dependsOn: [ DefaultNetworkSecurityGroup, DefaultRouteTable ]
steps:
- task: AzurePowerShell@4
displayName: "Virtual Network"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/LandingZone/definition.json" -ModuleConfigurationName "VirtualNetwork"'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_SUBSCRIPTIONS:VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: WorkloadPeeringToSharedServices
pool:
name: 'vdc-self-hosted'
dependsOn: 'VirtualNetwork'
steps:
- task: AzurePowerShell@4
displayName: "Workload Virtual Network Peering to Shared Services"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/LandingZone/definition.json" -ModuleConfigurationName "LocalVirtualNetworkPeering"'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_SUBSCRIPTIONS:VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)
- job: SharedServicesPeeringToWorkload
pool:
name: 'vdc-self-hosted'
dependsOn: 'VirtualNetwork'
steps:
- task: AzurePowerShell@4
displayName: "Shared Services Virtual Network Peering to Workload"
inputs:
azureSubscription: 'vdc2-spoke1'
ScriptType: 'FilePath'
ScriptPath: 'Orchestration/OrchestrationService/ModuleConfigurationDeployment.ps1'
ScriptArguments: '-DefinitionPath "Environments/ASE_SQLDB/LandingZone/definition.json" -ModuleConfigurationName "RemoteVirtualNetworkPeering"'
azurePowerShellVersion: 'LatestVersion'
env:
VDC_SUBSCRIPTIONS: $(VDC_SUBSCRIPTIONS)
VDC_SUBSCRIPTIONS:VDC_TOOLKIT_SUBSCRIPTION: $(VDC_TOOLKIT_SUBSCRIPTION)
DEPLOYMENT_USER_ID: $(DEPLOYMENT_USER_ID)
ADMIN_USER_PWD: $(ADMIN_USER_PWD)
DOMAIN_ADMIN_USER_PWD: $(DOMAIN_ADMIN_USER_PWD)
TENANT_ID: $(TENANT_ID)

Просмотреть файл

@ -5,6 +5,7 @@
"Name": "DiagnosticStorageAccount",
"ModuleDefinitionName": "StorageAccounts",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.DiagnosticStorageAccount.ResourceGroup}",
"DependsOn": [],
"Comments": "Storage Account that is used to store diagnostic information as raw logs",
"Version": "2.0",
"Policies": {
@ -354,10 +355,7 @@
{
"Name": "WindowsJumpboxKek",
"DependsOn": [
"KeyVault",
"VirtualNetwork",
"DiagnosticStorageAccount",
"LogAnalytics"
"KeyVault"
],
"Script": {
"Command": "../../Modules/KeyVault/2.0/Scripts/create.keys.ps1",
@ -372,10 +370,7 @@
{
"Name": "LinuxJumpboxKek",
"DependsOn": [
"KeyVault",
"VirtualNetwork",
"DiagnosticStorageAccount",
"LogAnalytics"
"KeyVault"
],
"Script": {
"Command": "../../Modules/KeyVault/2.0/Scripts/create.keys.ps1",
@ -390,10 +385,7 @@
{
"Name": "ActiveDirectoryKek",
"DependsOn": [
"KeyVault",
"VirtualNetwork",
"DiagnosticStorageAccount",
"LogAnalytics"
"KeyVault"
],
"Script": {
"Command": "../../Modules/KeyVault/2.0/Scripts/create.keys.ps1",
@ -408,10 +400,7 @@
{
"Name": "ActiveDirectoryDomainServicesKek",
"DependsOn": [
"KeyVault",
"VirtualNetwork",
"DiagnosticStorageAccount",
"LogAnalytics"
"KeyVault"
],
"Script": {
"Command": "../../Modules/KeyVault/2.0/Scripts/create.keys.ps1",
@ -429,20 +418,16 @@
"Updates": "KeyVault",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.KeyVault.ResourceGroup}",
"DependsOn": [
"VirtualNetwork",
"KeyVault",
"WindowsJumpbox",
"LinuxJumpbox",
"ActiveDirectoryVM",
"EncryptActiveDirectory",
"InstallActiveDirectory",
"ActiveDirectoryDomainServicesVMs",
"EncryptActiveDirectoryDomainServices",
"InstallActiveDirectoryDomainServices",
"ActiveDirectoryDomainServicesKek",
"WindowsJumpboxKek",
"LinuxJumpboxKek",
"ActiveDirectoryKek",
"VirtualNetwork"
"ActiveDirectoryKek"
],
"Deployment": {
"OverrideParameters": {
@ -496,7 +481,8 @@
"DiagnosticStorageAccount",
"LogAnalytics",
"KeyVault",
"ArtifactsStorageAccount"
"ArtifactsStorageAccount",
"WindowsJumpbox"
],
"Comments": "Creates Active Directory Domain Services VMs",
"Deployment": {
@ -566,13 +552,8 @@
"ModuleDefinitionName": "VirtualMachineKeyEncryptionKey",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.ActiveDirectory.ResourceGroup}",
"DependsOn": [
"VirtualNetwork",
"DiagnosticStorageAccount",
"LogAnalytics",
"EnableDnsServersOnVirtualNetwork",
"KeyVault",
"ArtifactsStorageAccount",
"ActiveDirectoryVM"
"ActiveDirectoryVM",
"ActiveDirectoryKek"
],
"Comments": "Encrypts VMs using bitlocker",
"Deployment": {
@ -600,12 +581,6 @@
"ModuleDefinitionName": "ActiveDirectory",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.ActiveDirectory.ResourceGroup}",
"DependsOn": [
"VirtualNetwork",
"DiagnosticStorageAccount",
"LogAnalytics",
"KeyVault",
"ArtifactsStorageAccount",
"ActiveDirectoryVM",
"EncryptActiveDirectory"
],
"Comments": "Creates Active Directory Domain Services VMs",
@ -651,8 +626,6 @@
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.ResourceGroup}",
"DependsOn": [
"InstallActiveDirectory",
"ActiveDirectoryVM",
"EncryptActiveDirectory",
"VirtualNetwork"
],
"Deployment": {
@ -663,11 +636,21 @@
}
}
},
{
"Name": "RegisterAzureBastionFeature",
"Enabled": false,
"Script": {
"Command": "../../Modules/AzureBastion/2.0/Scripts/RegisterProviderFeature.ps1",
"Arguments": {}
}
},
{
"Name": "AzureBastion",
"Enabled": false,
"ModuleDefinitionName": "AzureBastion",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.AzureBastion.ResourceGroup}",
"DependsOn": [
"RegisterAzureBastionFeature",
"VirtualNetwork"
],
"Deployment": {
@ -675,6 +658,9 @@
"azureBastionName": {
"value": "${Parameters.ModuleConfigurationParameters.AzureBastion.Name}"
},
"location": {
"value": "${Parameters.ModuleConfigurationParameters.AzureBastion.Location}"
},
"vNetId": {
"value": "reference(VirtualNetwork.vNetResourceId)"
}
@ -689,12 +675,9 @@
"VirtualNetwork",
"DiagnosticStorageAccount",
"LogAnalytics",
"InstallActiveDirectory",
"ActiveDirectoryVM",
"EncryptActiveDirectory",
"EnableDnsServersOnVirtualNetwork",
"KeyVault",
"ArtifactsStorageAccount"
"ArtifactsStorageAccount",
"JumpboxASG"
],
"Comments": "Creates Windows Jumpbox",
"Deployment": {
@ -766,20 +749,12 @@
},
{
"Name": "EncryptWindowsJumpbox",
"Enabled": false,
"ModuleDefinitionName": "VirtualMachineKeyEncryptionKey",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.Jumpbox.ResourceGroup}",
"DependsOn": [
"VirtualNetwork",
"DiagnosticStorageAccount",
"LogAnalytics",
"InstallActiveDirectory",
"ActiveDirectoryVM",
"EncryptActiveDirectory",
"EnableDnsServersOnVirtualNetwork",
"KeyVault",
"ArtifactsStorageAccount",
"ActiveDirectoryDomainServicesVMs",
"WindowsJumpbox"
"WindowsJumpbox",
"WindowsJumpboxKek"
],
"Comments": "Encrypts VMs using bitlocker",
"Deployment": {
@ -810,13 +785,9 @@
"VirtualNetwork",
"DiagnosticStorageAccount",
"LogAnalytics",
"InstallActiveDirectory",
"ActiveDirectoryVM",
"EncryptActiveDirectory",
"EnableDnsServersOnVirtualNetwork",
"KeyVault",
"ArtifactsStorageAccount",
"AzureBastion"
"JumpboxASG"
],
"Comments": "Creates Linux Jumpbox",
"Deployment": {
@ -889,18 +860,11 @@
{
"Name": "EncryptLinuxJumpbox",
"ModuleDefinitionName": "VirtualMachineKeyEncryptionKey",
"Enabled": false,
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.Jumpbox.ResourceGroup}",
"DependsOn": [
"VirtualNetwork",
"DiagnosticStorageAccount",
"LogAnalytics",
"InstallActiveDirectory",
"ActiveDirectoryVM",
"EncryptActiveDirectory",
"EnableDnsServersOnVirtualNetwork",
"KeyVault",
"ArtifactsStorageAccount",
"LinuxJumpbox"
"LinuxJumpbox",
"LinuxJumpboxKek"
],
"Comments": "Encrypts VMs using bitlocker",
"Deployment": {
@ -932,9 +896,10 @@
"DiagnosticStorageAccount",
"LogAnalytics",
"WindowsJumpbox",
"EnableDnsServersOnVirtualNetwork",
"KeyVault",
"ArtifactsStorageAccount"
"ArtifactsStorageAccount",
"DomainControllerASG",
"EnableDnsServersOnVirtualNetwork"
],
"Comments": "Creates Active Directory Domain Services VMs",
"Deployment": {
@ -994,7 +959,7 @@
"value": "${Parameters.ModuleConfigurationParameters.ActiveDirectoryDomainServices.AddsIPAddressStart}"
},
"applicationSecurityGroupId": {
"value": "reference(JumpboxASG.applicationSecurityGroupResourceId)"
"value": "reference(DomainControllerASG.applicationSecurityGroupResourceId)"
},
"adminUsername": {
"value": "${Parameters.ModuleConfigurationParameters.ActiveDirectoryDomainServices.AdminUsername}"
@ -1010,17 +975,8 @@
"ModuleDefinitionName": "VirtualMachineKeyEncryptionKey",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.ActiveDirectoryDomainServices.ResourceGroup}",
"DependsOn": [
"VirtualNetwork",
"DiagnosticStorageAccount",
"LogAnalytics",
"InstallActiveDirectory",
"ActiveDirectoryVM",
"EncryptActiveDirectory",
"WindowsJumpbox",
"EnableDnsServersOnVirtualNetwork",
"KeyVault",
"ArtifactsStorageAccount",
"ActiveDirectoryDomainServicesVMs"
"ActiveDirectoryDomainServicesVMs",
"ActiveDirectoryDomainServicesKek"
],
"Comments": "Encrypts Active Directory Domain Services VMs using bitlocker",
"Deployment": {
@ -1051,18 +1007,7 @@
"ModuleDefinitionName": "ActiveDirectoryDomainServices",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.ActiveDirectoryDomainServices.ResourceGroup}",
"DependsOn": [
"InstallActiveDirectory",
"ActiveDirectoryVM",
"EncryptActiveDirectory",
"EnableDnsServersOnVirtualNetwork",
"WindowsJumpbox",
"VirtualNetwork",
"DiagnosticStorageAccount",
"LogAnalytics",
"KeyVault",
"ArtifactsStorageAccount",
"EncryptActiveDirectoryDomainServices",
"ActiveDirectoryDomainServicesVMs"
"EncryptActiveDirectoryDomainServices"
],
"Comments": "Installs Active Directory Domain Services",
"Deployment": {

Просмотреть файл

@ -77,7 +77,21 @@
"UK South",
"West Central US",
"West Europe",
"West US 2"
"West US 2",
"West US"
]
},
"AzureBastion": {
"ResourceGroup": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.ResourceGroup}",
"Name": "${Parameters.InstanceName}-bastion",
"Location": "West US",
"ListOfAllowedRegions": [
"West US",
"East US",
"West Europe",
"South Central US",
"Australia East",
"Japan East"
]
},
"ApplicationSecurityGroups": {
@ -382,7 +396,7 @@
"EnableVmProtection": false,
"Subnets": [
{
"name": "${Parameters.DeploymentName}",
"name": "shrdsvcs",
"addressPrefix": "172.0.0.0/24",
"networkSecurityGroupName": "${Parameters.ModuleConfigurationParameters.NetworkSecurityGroups.SharedServices.Name}",
"routeTableName": "${Parameters.ModuleConfigurationParameters.RouteTables.SharedServices.Name}",
@ -428,6 +442,13 @@
"networkSecurityGroupName": "",
"routeTableName": "",
"serviceEndpoints": []
},
{
"name": "AzureBastionSubnet",
"addressPrefix": "172.0.5.0/24",
"networkSecurityGroupName": "",
"routeTableName": "",
"serviceEndpoints": []
}
],
"DnsServers": [
@ -626,7 +647,7 @@
]
},
"KeyVault": {
"Name": "${Parameters.InstanceName}-kv03",
"Name": "${Parameters.InstanceName}-kv",
"ResourceGroup": "${Parameters.InstanceName}-keyvault-rg",
"Sku": "Premium",
"EnableVaultForDeployment": true,
@ -672,7 +693,7 @@
"secretValue": "env(ADMIN_USER_PWD)"
},
{
"secretName": "${Parameters.ModuleConfigurationParameters.ActiveDirectory.DomainAdminUserName}",
"secretName": "env(DOMAIN_ADMIN_USERNAME)",
"secretValue": "env(DOMAIN_ADMIN_USER_PWD)"
},
{
@ -693,10 +714,6 @@
}
},
"ArtifactsStorageAccount": "file(../_Common/artifactsStorageAccount.json)",
"AzureBastion": {
"Name": "sharedsvcs-bastion",
"ResourceGroup": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.ResourceGroup}"
},
"Jumpbox": {
"ResourceGroup": "${Parameters.InstanceName}-jumpbox-rg",
"AdminUsername": "${Parameters.ModuleConfigurationParameters.KeyVault.SecretsObject.Secrets[0].secretName}",
@ -742,10 +759,10 @@
"ResourceGroup": "${Parameters.InstanceName}-adds-rg",
"Comments": "Windows VM name cannot exceed 13 characters.",
"PrimaryDomainControllerIP": "172.0.0.10",
"DomainName": "fontoso.com",
"DomainName": "contoso.com",
"ADSitename": "Cloud-Site",
"CloudZone": "fontosocloud.com",
"DomainAdminUsername": "fontoso",
"CloudZone": "contosocloud.com",
"DomainAdminUsername": "env(DOMAIN_ADMIN_USERNAME)",
"DomainAdminPassword": {
"keyVault": {
"id": "reference(KeyVault.keyVaultResourceId)"

Просмотреть файл

@ -325,7 +325,7 @@
"Subscription": "OnPremises",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.OnPremisesInformation.VirtualNetworkGateway.ResourceGroup}",
"DependsOn": [
"VirtualNetworkGateway"
"LocalVirtualNetworkGatewayConnection"
],
"Deployment": {
"OverrideParameters": {
@ -456,10 +456,7 @@
{
"Name": "WindowsJumpboxKek",
"DependsOn": [
"KeyVault",
"VirtualNetwork",
"DiagnosticStorageAccount",
"LogAnalytics"
"KeyVault"
],
"Script": {
"Command": "../../Modules/KeyVault/2.0/Scripts/create.keys.ps1",
@ -474,10 +471,7 @@
{
"Name": "LinuxJumpboxKek",
"DependsOn": [
"KeyVault",
"VirtualNetwork",
"DiagnosticStorageAccount",
"LogAnalytics"
"KeyVault"
],
"Script": {
"Command": "../../Modules/KeyVault/2.0/Scripts/create.keys.ps1",
@ -492,10 +486,7 @@
{
"Name": "ActiveDirectoryDomainServicesKek",
"DependsOn": [
"KeyVault",
"VirtualNetwork",
"DiagnosticStorageAccount",
"LogAnalytics"
"KeyVault"
],
"Script": {
"Command": "../../Modules/KeyVault/2.0/Scripts/create.keys.ps1",
@ -513,11 +504,10 @@
"Updates": "KeyVault",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.KeyVault.ResourceGroup}",
"DependsOn": [
"VirtualNetwork",
"KeyVault",
"WindowsJumpbox",
"LinuxJumpbox",
"ActiveDirectoryDomainServicesVMs",
"EncryptActiveDirectoryDomainServices",
"LinuxJumpbox",
"InstallActiveDirectoryDomainServices",
"ActiveDirectoryDomainServicesKek",
"WindowsJumpboxKek",
@ -566,11 +556,19 @@
}
}
},
{
"Name": "RegisterAzureBastionFeature",
"Script": {
"Command": "../../Modules/AzureBastion/2.0/Scripts/RegisterProviderFeature.ps1",
"Arguments": {}
}
},
{
"Name": "AzureBastion",
"ModuleDefinitionName": "AzureBastion",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.AzureBastion.ResourceGroup}",
"DependsOn": [
"RegisterAzureBastionFeature",
"VirtualNetwork"
],
"Deployment": {
@ -578,6 +576,9 @@
"azureBastionName": {
"value": "${Parameters.ModuleConfigurationParameters.AzureBastion.Name}"
},
"location": {
"value": "${Parameters.ModuleConfigurationParameters.AzureBastion.Location}"
},
"vNetId": {
"value": "reference(VirtualNetwork.vNetResourceId)"
}
@ -592,11 +593,9 @@
"VirtualNetwork",
"DiagnosticStorageAccount",
"LogAnalytics",
"ActiveDirectoryDomainServicesVMs",
"EncryptActiveDirectoryDomainServices",
"InstallActiveDirectoryDomainServices",
"KeyVault",
"ArtifactsStorageAccount"
"ArtifactsStorageAccount",
"JumpboxASG"
],
"Comments": "Creates Windows Jumpbox",
"Deployment": {
@ -670,16 +669,10 @@
"Name": "EncryptWindowsJumpbox",
"ModuleDefinitionName": "VirtualMachineKeyEncryptionKey",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.Jumpbox.ResourceGroup}",
"Enabled": false,
"DependsOn": [
"VirtualNetwork",
"DiagnosticStorageAccount",
"LogAnalytics",
"KeyVault",
"ArtifactsStorageAccount",
"ActiveDirectoryDomainServicesVMs",
"EncryptActiveDirectoryDomainServices",
"InstallActiveDirectoryDomainServices",
"WindowsJumpbox"
"WindowsJumpbox",
"WindowsJumpboxKek"
],
"Comments": "Encrypts VMs using bitlocker",
"Deployment": {
@ -712,9 +705,7 @@
"LogAnalytics",
"KeyVault",
"ArtifactsStorageAccount",
"ActiveDirectoryDomainServicesVMs",
"EncryptActiveDirectoryDomainServices",
"InstallActiveDirectoryDomainServices"
"JumpboxASG"
],
"Comments": "Creates Linux Jumpbox",
"Deployment": {
@ -788,16 +779,10 @@
"Name": "EncryptLinuxJumpbox",
"ModuleDefinitionName": "VirtualMachineKeyEncryptionKey",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.Jumpbox.ResourceGroup}",
"Enabled": false,
"DependsOn": [
"VirtualNetwork",
"DiagnosticStorageAccount",
"LogAnalytics",
"KeyVault",
"ArtifactsStorageAccount",
"LinuxJumpbox",
"ActiveDirectoryDomainServicesVMs",
"EncryptActiveDirectoryDomainServices",
"InstallActiveDirectoryDomainServices"
"LinuxJumpboxKek"
],
"Comments": "Encrypts VMs using bitlocker",
"Deployment": {
@ -829,9 +814,9 @@
"DiagnosticStorageAccount",
"LogAnalytics",
"WindowsJumpbox",
"LinuxJumpbox",
"KeyVault",
"ArtifactsStorageAccount"
"ArtifactsStorageAccount",
"DomainControllerASG"
],
"Comments": "Creates Active Directory Domain Services VMs",
"Deployment": {
@ -907,14 +892,8 @@
"ModuleDefinitionName": "VirtualMachineKeyEncryptionKey",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.ActiveDirectoryDomainServices.ResourceGroup}",
"DependsOn": [
"VirtualNetwork",
"DiagnosticStorageAccount",
"LogAnalytics",
"KeyVault",
"ArtifactsStorageAccount",
"ActiveDirectoryDomainServicesVMs",
"LinuxJumpbox",
"WindowsJumpbox"
"ActiveDirectoryDomainServicesKek"
],
"Comments": "Encrypts Active Directory Domain Services VMs using bitlocker",
"Deployment": {
@ -945,15 +924,7 @@
"ModuleDefinitionName": "ActiveDirectoryDomainServices",
"ResourceGroupName": "${Parameters.ModuleConfigurationParameters.ActiveDirectoryDomainServices.ResourceGroup}",
"DependsOn": [
"WindowsJumpbox",
"LinuxJumpbox",
"VirtualNetwork",
"DiagnosticStorageAccount",
"LogAnalytics",
"KeyVault",
"ArtifactsStorageAccount",
"EncryptActiveDirectoryDomainServices",
"ActiveDirectoryDomainServicesVMs"
"EncryptActiveDirectoryDomainServices"
],
"Comments": "Installs Active Directory Domain Services",
"Deployment": {

Просмотреть файл

@ -11,14 +11,14 @@
"PrimaryDomainControllerIP": "192.168.1.4",
"DomainName": "contoso.com",
"ADSitename": "Cloud-Site",
"DomainAdminUserName": "contoso"
"DomainAdminUserName": "env(DOMAIN_ADMIN_USERNAME)"
},
"Network": {
"AddressPrefix": "192.168.1.0/28"
},
"VirtualNetworkGateway": {
"Name": "jch-onprem-gw",
"ResourceGroup": "jch-onprem-net-rg"
"Name": "cnts-onprem-gw",
"ResourceGroup": "cnts-onprem-net-rg"
},
"SubscriptionId": "${Subscriptions.OnPremises.SubscriptionId}"
},
@ -95,6 +95,19 @@
"West US 2"
]
},
"AzureBastion": {
"ResourceGroup": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.ResourceGroup}",
"Name": "${Parameters.InstanceName}-bastion",
"Location": "West US",
"ListOfAllowedRegions": [
"West US",
"East US",
"West Europe",
"South Central US",
"Australia East",
"Japan East"
]
},
"ApplicationSecurityGroups": {
"ResourceGroup": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.ResourceGroup}",
"Jumpbox": {
@ -473,7 +486,7 @@
"EnableVmProtection": false,
"Subnets": [
{
"name": "${Parameters.DeploymentName}",
"name": "shrdsvcs",
"addressPrefix": "172.0.0.0/24",
"networkSecurityGroupName": "${Parameters.ModuleConfigurationParameters.NetworkSecurityGroups.SharedServices.Name}",
"routeTableName": "${Parameters.ModuleConfigurationParameters.RouteTables.SharedServices.Name}",
@ -519,6 +532,13 @@
"networkSecurityGroupName": "",
"routeTableName": "",
"serviceEndpoints": []
},
{
"name": "AzureBastionSubnet",
"addressPrefix": "172.0.5.0/24",
"networkSecurityGroupName": "",
"routeTableName": "",
"serviceEndpoints": []
}
],
"DnsServers": [
@ -784,10 +804,6 @@
}
},
"ArtifactsStorageAccount": "file(../_Common/artifactsStorageAccount.json)",
"AzureBastion": {
"Name": "sharedsvcs-bastion",
"ResourceGroup": "${Parameters.ModuleConfigurationParameters.VirtualNetwork.ResourceGroup}"
},
"Jumpbox": {
"ResourceGroup": "${Parameters.InstanceName}-jumpbox-rg",
"AdminUsername": "${Parameters.ModuleConfigurationParameters.KeyVault.SecretsObject.Secrets[0].secretName}",

Просмотреть файл

@ -18,6 +18,12 @@
"SubscriptionId": "00000000000000000000000",
"Location": "West US 2"
},
"NTier_IaaS": {
"Comments": "Workload subscription and tenant information",
"TenantId": "00000000000000000000000",
"SubscriptionId": "00000000000000000000000",
"Location": "West US 2"
},
"Artifacts": {
"Comments": "Subscription and tenant information where the Artifacts Storage Account will reside",
"TenantId": "00000000000000000000000",

Просмотреть файл

@ -115,6 +115,11 @@ Describe "Template: $template - Active Directory Domain Services" -Tags Unit {
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
if ($requiredParametersInTemplateFile.Count -gt $allParametersInParametersFile.Count) {
Write-Host "Mismatch found, parameters from parameter file are more than the expected in the template"
Write-Host "Required parameters are: $(ConvertTo-Json $requiredParametersInTemplateFile)"
Write-Host "Parameters from parameter file are: $(ConvertTo-Json $allParametersInParametersFile)"
}
$requiredParametersInTemplateFile.Count | Should Not BeGreaterThan $allParametersInParametersFile.Count;
}
}

Просмотреть файл

@ -14,15 +14,18 @@
"artifactsStorageAccountKey": {
"value": ""
},
"addsAddressStart": {
"value": "11.4.0.46"
},
"domainName": {
"value": "contoso.com"
},
"primaryDCIP": {
"value": "192.168.1.4"
},
"addsAddressStart": {
"value": "11.4.0.46"
},
"addsInstallDriveLetter": {
"value": "F:"
},
"ADSitename": {
"value": "Cloud-Site"
},

Просмотреть файл

@ -28,7 +28,8 @@
"UK South",
"West Central US",
"West Europe",
"West US 2"
"West US 2",
"West US"
],
"metadata": {
"description": "Required. Specifies the region for your Automation Account"

Просмотреть файл

@ -0,0 +1,15 @@
$installed = Get-AzProviderFeature -ProviderNamespace Microsoft.Network | Where-Object -Property "FeatureName" -EQ "AllowBastionHost"
if ($null -eq $installed) {
Register-AzProviderFeature -FeatureName AllowBastionHost -ProviderNamespace Microsoft.Network
Register-AzResourceProvider -ProviderNamespace Microsoft.Network
}
While ($null -eq $installed) {
$installed = Get-AzProviderFeature -ProviderNamespace Microsoft.Network | Where-Object -Property "FeatureName" -EQ "AllowBastionHost"
$isInstalled = $null -ne $installed
Write-Host "Is installed: $isInstalled"
Start-Sleep -Seconds 20
}
Write-Host "Installation complete"

Просмотреть файл

@ -17,8 +17,16 @@
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"allowedValues": [
"West US",
"East US",
"West Europe",
"South Central US",
"Australia East",
"Japan East"
],
"metadata": {
"description": "Optional. Location for all resources."
"description": "Optional. Location for Azure Bastion, is currently limited to a small subset of regions."
}
}
},
@ -26,17 +34,20 @@
"resources": [
{
"type": "Microsoft.Network/publicIPAddresses",
"apiVersion": "2018-08-01",
"apiVersion": "2019-02-01",
"name": "[concat(parameters('azureBastionName'), '-pip')]",
"location": "[parameters('location')]",
"sku": {
"name": "Standard"
},
"properties": {
"publicIPAllocationMethod": "Dynamic"
"publicIPAllocationMethod": "Static"
}
},
{
"type": "Microsoft.Network/bastionHosts",
"name": "[parameters('azureBastionName')]",
"apiVersion": "2019-04-01",
"apiVersion": "2018-10-01",
"location": "[parameters('location')]",
"dependsOn": [
"[concat(parameters('azureBastionName'), '-pip')]"
@ -44,14 +55,14 @@
"properties": {
"ipConfigurations": [
{
"name": "IpConf",
"properties": {
"subnet": {
"id": "[concat(parameters('vNetId'), '/subnets/AzureBastionSubnet')]"
},
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses', concat(parameters('azureBastionName'), '-pip'))]"
},
"privateIPAllocationMethod": "Dynamic"
}
}
}
]

Просмотреть файл

@ -0,0 +1,35 @@
name: $(Build.DefinitionName)-$(SourceBranchName)-$(Date:yyyyMMdd).$(Rev:rr)
variables:
ModuleName: KeyVault
ModuleVersion: 2.0
RepoName: azure-devops
ModulePath: modules/$(ModuleName)/$(ModuleVersion)
ArtifactName: contents
resources:
repositories:
- repository: main
type: git
name: '$(RepoName)'
trigger:
branches:
include:
- master
- '*'
paths:
include:
- modules/KeyVault/2.0
jobs:
- job: BuildModule
displayName: Build Module
workspace:
clean: all
steps:
- template: /azure-devops/ci/buildmodule.yaml
parameters:
ModulePath: $(ModulePath)
ArtifactName: $(ArtifactName)

Просмотреть файл

@ -0,0 +1,37 @@
{
"policies": [
{
"name": "kvPermittedResourceTypes",
"description": "Policy to prevent the creation of unauthorized resource types within the resource group.",
"rules": {
"if": {
"not": {
"field": "type",
"in": [
"Microsoft.KeyVault/vaults",
"Microsoft.Storage/storageAccounts"
]
}
},
"then": {
"effect": "audit"
}
}
},
{
"name": "denyPublicIP",
"description": "Policy to prevent the creation of public ip resources",
"rules": {
"if": {
"field": "type",
"in": [
"Microsoft.Network/publicIPAddresses"
]
},
"then": {
"effect": "audit"
}
}
}
]
}

Просмотреть файл

@ -0,0 +1,41 @@
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string]
$VaultName,
[Parameter(Mandatory=$true)]
[string]
$KeyName,
[Parameter(Mandatory=$false)]
[string]
$Destination,
[Parameter(Mandatory=$false)]
[bool]
$ReplaceExistingKey = $false
)
if ($null -eq $Destination) {
$Destination = "HSM";
}
try {
$result = `
(Get-AzKeyVaultKey `
-VaultName $VaultName `
-Name $KeyName `
-ErrorAction SilentlyContinue).Id;
if (($null -eq $result) -or `
$ReplaceExistingKey) {
$result = (Add-AzKeyVaultKey `
-VaultName $VaultName `
-Name $KeyName `
-Destination $Destination).Id;
}
return $result
}
catch {
throw $_;
}

Просмотреть файл

@ -0,0 +1,217 @@
<#
.NOTES
==============================================================================================
Copyright(c) Microsoft Corporation. All rights reserved.
File: key.vault.backup.ps1
Purpose: Key Vault Backup Automation Script
Version: 1.0.0.0 - 1st April 2019 - Azure Virtual Datacenter Development Team
==============================================================================================
.SYNOPSIS
Key Vault Backup Automation Script
.DESCRIPTION
Key Vault Backup Automation Script
Deployment steps of the script are outlined below.
1) Set Azure KeyVault Parameters
2) Setup Backup Directory
3) Backup Key Vault Secrets
4) Copy Files to Azure Files
5) Create Backup Folder
6) Upload Files
.PARAMETER KeyVaultName
Specify the Azure Key Vault Name parameter.
.PARAMETER KeyVaultResourceGroup
Specify the Key Vault Resource Group Name parameter.
.PARAMETER StorageAccountName
Specify the Storage Account Name parameter.
.PARAMETER StorageResourceGroup
Specify the Storage Resource Group Name parameter.
.PARAMETER fileshareName
Specify the File Share Name parameter.
.PARAMETER backupFolder
Specify the Backup Folder parameter.
.PARAMETER tempRestoreFolder
Specify the Temp Restore Folder parameter.
.EXAMPLE
Default:
C:\PS>.\key.vault.backup.ps1 `
-KeyVaultName <"KeyVaultName"> `
-KeyVaultResourceGroup <"KeyVaultResourceGroup> `
-StorageAccountName <"StorageAccountName"> `
-StorageResourceGroup <"StorageResourceGroup"> `
-fileshareName <"fileshareName"> `
-backupFolder <"backupFolder">
#>
#Requires -Version 5
#Requires -Module AzureRM.KeyVault
#Requires -Module AzureRM.Storage
#Requires -Module Azure.Storage
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true)]
[string]$keyVaultName,
[Parameter(Mandatory = $true)]
[string]$keyVaultResourceGroup,
[Parameter(Mandatory = $true)]
[string]$StorageAccountName,
[Parameter(Mandatory = $true)]
[string]$StorageResourceGroup,
[Parameter(Mandatory = $true)]
[string]$fileshareName,
[string]$backupFolder = "$env:Temp\KeyVaultBackup"
)
#region - Setup Backup Directory
if (test-path $backupFolder)
{
$paramRemoveItem = @{
Path = $backupFolder
Recurse = $true
Force = $true
}
Remove-Item @paramRemoveItem
}
#endregion
#region - Backup Key Vault Secrets
$paramNewItem = @{
ItemType = 'Directory'
Force = $true
Path = $backupFolder
}
New-Item @paramNewItem | Out-Null
Write-Output "Starting backup of KeyVault to local directory"
#region - Certificates
$paramGetAzureKeyVaultCertificate = @{
VaultName = $keyvaultName
}
$certificates = Get-AzureKeyVaultCertificate @paramGetAzureKeyVaultCertificate
foreach ($cert in $certificates)
{
$paramBackupAzureKeyVaultCertificate = @{
Name = $cert.name
VaultName = $keyvaultName
OutputFile = "$backupFolder\certificate-$($cert.name)"
}
Backup-AzureKeyVaultCertificate @paramBackupAzureKeyVaultCertificate | Out-Null
}
#endregion
#region - Secrets
$paramGetAzureKeyVaultSecret = @{
VaultName = $keyvaultName
}
$secrets = Get-AzureKeyVaultSecret @paramGetAzureKeyVaultSecret
foreach ($secret in $secrets)
{
#Exclude any secerets automatically generated when creating a cert, as these cannot be backed up
if (-not ($certificates.Name -contains $secret.name))
{
$paramBackupAzureKeyVaultSecret = @{
Name = $secret.name
VaultName = $keyvaultName
OutputFile = "$backupFolder\secret-$($secret.name)"
}
Backup-AzureKeyVaultSecret @paramBackupAzureKeyVaultSecret | Out-Null
}
}
#endregion
#region - Keys
$paramGetAzureKeyVaultKey = @{
VaultName = $keyvaultName
}
$keys = Get-AzureKeyVaultKey @paramGetAzureKeyVaultKey
foreach ($kvkey in $keys)
{
#Exclude any keys automatically generated when creating a cert, as these cannot be backed up
if (-not ($certificates.Name -contains $kvkey.name))
{
$paramBackupAzureKeyVaultKey = @{
Name = $kvkey.name
VaultName = $keyvaultName
OutputFile = "$backupFolder\key-$($kvkey.name)"
}
Backup-AzureKeyVaultKey @paramBackupAzureKeyVaultKey | Out-Null
}
}
#endregion
Write-Output "Local file backup complete"
#endregion
#region - Copy Files to Azure Files
Write-Output "Starting upload of backup to Azure Files"
$paramGetAzureRmStorageAccount = @{
ResourceGroupName = $storageResourceGroup
Name = $storageAccountName
}
$storageAccount = Get-AzureRmStorageAccount @paramGetAzureRmStorageAccount
$files = Get-ChildItem $backupFolder
$backupFolderName = Split-Path $backupFolder -Leaf
#endregion
#region - Create Backup Folder
$paramGetAzureStorageFile = @{
Context = $storageAccount.Context
ShareName = $fileshareName
Path = $backupFolderName
}
$backupFolderTest = Get-AzureStorageFile @paramGetAzureStorageFile
if (-not $backupFolderTest)
{
$paramNewAzureStorageDirectory = @{
Context = $storageAccount.Context
ShareName = $fileshareName
Path = $backupFolderName
}
New-AzureStorageDirectory @paramNewAzureStorageDirectory
}
#endregion
#region - Upload Files
foreach ($file in $files)
{
$paramSetAzureStorageFileContent = @{
Context = $storageAccount.Context
ShareName = $fileshareName
Source = $file.FullName
Path = "$backupFolderName\$($file.name)"
Force = $true
}
Set-AzureStorageFileContent @paramSetAzureStorageFileContent
}
$paramRemoveItem = @{
Path = $backupFolder
Recurse = $true
Force = $true
}
Remove-Item @paramRemoveItem
Write-Output "Upload complete"
Write-Output "Backup Complete"
#endregion

Просмотреть файл

@ -0,0 +1,80 @@
<#
.NOTES
==============================================================================================
Copyright(c) Microsoft Corporation. All rights reserved.
File: key.vault.log.analytics.register.ps1
Purpose: Register Key Vault with Log Analytics Deployment Automation Script
Version: 1.0.0.0 - 1st April 2019 - Azure Virtual Datacenter Development Team
==============================================================================================
.SYNOPSIS
Register Key Vault with Log Analytics Deployment Automation Script
.DESCRIPTION
Register Key Vault with Log Analytics Deployment Automation Script
Deployment steps of the script are outlined below.
1) Register Key Vault with Log Analytics
.PARAMETER keyVaultName
Specify the key Vault Name parameter.
.PARAMETER diagstorageAccountName
Specify the diagnostic Storage Account Name parameter.
.PARAMETER omsWorkspaceName
Specify the Log Analytics Workspace Name parameter.
.EXAMPLE
Default:
C:\PS>.\key.vault.log.analytics.register.ps1 `
-keyVaultName <"keyVaultName"> `
-diagstorageAccountName <"diagstorageAccountName"> `
-omsWorkspaceName <"omsWorkspaceName">
#>
#Requires -Version 5
#Requires -Module AzureRM.Resources
#Requires -Module AzureRM.Insights
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true)]
[string]$keyVaultName,
[Parameter(Mandatory = $true)]
[string]$diagstorageAccountName,
[Parameter(Mandatory = $true)]
[string]$omsWorkspaceName
)
#region - Register Keyvault with Log Analytics
$paramGetAzureRmResource = @{
ResourceName = $keyVaultName
ResourceType = "Microsoft.DocumentDb/databaseAccounts"
}
$KeyVault = Get-AzureRmResource @paramGetAzureRmResource
$paramGetAzureRmResource = @{
ResourceName = $diagstorageAccountName
ResourceType = "Microsoft.Storage/storageAccounts"
}
$StorageAccount = Get-AzureRmResource @paramGetAzureRmResource
$paramGetAzureRmResource = @{
ResourceName = $omsWorkspaceName
ResourceType = "Microsoft.OperationalInsights/workspaces"
}
$WorkspaceName = Get-AzureRmResource @paramGetAzureRmResource
$paramSetAzureRmDiagnosticSetting = @{
ResourceId = $KeyVault.ResourceId
StorageAccountId = $StorageAccount.Id
WorkspaceId = $WorkspaceName.Id
Enabled = $true
}
Set-AzureRmDiagnosticSetting @paramSetAzureRmDiagnosticSetting
#endregion

Просмотреть файл

@ -0,0 +1,187 @@
<#
.NOTES
==============================================================================================
Copyright(c) Microsoft Corporation. All rights reserved.
File: key.vault.restore.ps1
Purpose: Key Vault Restore Automation Script
Version: 1.0.0.0 - 1st April 2019 - Azure Virtual Datacenter Development Team
==============================================================================================
.SYNOPSIS
Key Vault Restore Automation Script
.DESCRIPTION
Key Vault Restore Automation Script
Deployment steps of the script are outlined below.
1) Set Azure Key Vault Parameters
2) Create temporary folder to download files
3) Download files from Azure File Share
4) Restore Key Vault Serects
.PARAMETER KeyVaultName
Specify the Azure Key Vault Name parameter.
.PARAMETER KeyVaultResourceGroup
Specify the Key Vault Resource Group Name parameter.
.PARAMETER StorageAccountName
Specify the Storage Account Name parameter.
.PARAMETER StorageResourceGroup
Specify the Storage Resource Group Name parameter.
.PARAMETER fileshareName
Specify the File Share Name parameter.
.PARAMETER backupFolder
Specify the Backup Folder parameter.
.PARAMETER tempRestoreFolder
Specify the Temp Restore Folder parameter.
.EXAMPLE
Default:
C:\PS>.\key.vault.restore.ps1 `
-KeyVaultName <"KeyVaultName"> `
-KeyVaultResourceGroup <"KeyVaultResourceGroup> `
-StorageAccountName <"StorageAccountName"> `
-StorageResourceGroup <"StorageResourceGroup"> `
-fileshareName <"fileshareName"> `
-backupFolder <"backupFolder"> `
-tempRestoreFolder <"tempRestoreFolder">
#>
#Requires -Version 5
#Requires -Module AzureRM.KeyVault
#Requires -Module AzureRM.Storage
#Requires -Module Azure.Storage
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true)]
[string]$KeyVaultName,
[Parameter(Mandatory = $true)]
[string]$KeyVaultResourceGroup,
[Parameter(Mandatory = $true)]
[string]$StorageAccountName,
[Parameter(Mandatory = $true)]
[string]$StorageResourceGroup,
[Parameter(Mandatory = $true)]
[string]$fileshareName,
[Parameter(Mandatory = $true)]
[string]$backupFolder,
[string]$tempRestoreFolder = "$env:Temp\KeyVaultRestore"
)
#region - Create temporary folder to download files
if (test-path $tempRestoreFolder)
{
$paramRemoveItem = @{
Path = $tempRestoreFolder
Recurse = $true
Force = $true
}
Remove-Item @paramRemoveItem
}
$paramNewItem = @{
ItemType = 'Directory'
Force = $true
Path = $tempRestoreFolder
}
New-Item @paramNewItem | Out-Null
Write-Output "Starting download of backup to Azure Files"
$paramGetAzureRmStorageAccount = @{
ResourceGroupName = $storageResourceGroup
Name = $storageAccountName
}
$storageAccount = Get-AzureRmStorageAccount @paramGetAzureRmStorageAccount
#endregion
#region - Download files from Azure File Share
$paramGetAzureStorageFile = @{
Context = $storageAccount.Context
ShareName = $fileshareName
Path = $backupFolderName
}
$backupFolderTest = Get-AzureStorageFile @paramGetAzureStorageFile
if (-not $backupFolderTest)
{
Write-Error "Backup folder in Azure File Share Not Found"
exit
}
$paramGetAzureStorageFile = @{
ShareName = $fileshareName
Path = $backupFolder
Context = $storageAccount.Context
}
$backupFiles = Get-AzureStorageFile @paramGetAzureStorageFile | Get-AzureStoragefile
foreach ($backupFile in $backupFiles)
{
Write-Output "downloading $backupFolder\$($backupFile.name)"
$paramGetAzureStorageFileContent = @{
ShareName = $fileshareName
Path = "$backupFolder\$($backupFile.name)"
Destination = "$tempRestoreFolder\$($backupFile.name)"
Context = $storageAccount.Context
}
Get-AzureStorageFileContent @paramGetAzureStorageFileContent
}
#endregion
#region - Restore secrets to Key Vault
Write-Output "Starting Restore"
$secrets = get-childitem $tempRestoreFolder | where-object { $_ -match "^(secret-)" }
$certificates = get-childitem $tempRestoreFolder | where-object { $_ -match "^(certificate-)" }
$keys = get-childitem $tempRestoreFolder | where-object { $_ -match "^(key-)" }
foreach ($secret in $secrets)
{
write-output "restoring $($secret.FullName)"
$paramRestoreAzureKeyVaultSecret = @{
VaultName = $keyvaultName
InputFile = $secret.FullName
}
Restore-AzureKeyVaultSecret @paramRestoreAzureKeyVaultSecret
}
foreach ($certificate in $certificates)
{
write-output "restoring $($certificate.FullName) "
$paramRestoreAzureKeyVaultCertificate = @{
VaultName = $keyvaultName
InputFile = $certificate.FullName
}
Restore-AzureKeyVaultCertificate @paramRestoreAzureKeyVaultCertificate
}
foreach ($key in $keys)
{
write-output "restoring $($key.FullName) "
$paramRestoreAzureKeyVaultKey = @{
VaultName = $keyvaultName
InputFile = $key.FullName
}
Restore-AzureKeyVaultKey @paramRestoreAzureKeyVaultKey
}
$paramRemoveItem = @{
Path = $tempRestoreFolder
Recurse = $true
Force = $true
}
Remove-Item @paramRemoveItem
Write-Output "Restore Complete"
#endregion

Просмотреть файл

@ -0,0 +1,78 @@
<#
.NOTES
==============================================================================================
Copyright(c) Microsoft Corporation. All rights reserved.
File: key.vault.secrect.rules.ps1
Purpose: Set Key Vault Secrets Automation Script
Version: 1.0.0.0 - 1st April 2019 - Azure Virtual Datacenter Development Team
==============================================================================================
.SYNOPSIS
Set Key Vault Secrets Automation Script
.DESCRIPTION
Set Key Vault Secrets Automation Script
Deployment steps of the script are outlined below.
1) Set Azure KeyVault Parameters
2) Create Azure KeyVault Secret
.PARAMETER KeyVaultName
Specify the Azure Key Vault Name parameter.
.EXAMPLE
Default:
C:\PS>.\key.vault.secrect.rules.ps1 `
-KeyVaultName <"KeyVaultName">
#>
#Requires -Version 5
#Requires -Module AzureRM.KeyVault
[CmdletBinding()]
param
(
[Parameter(Mandatory = $false)]
[string]$KeyVaultName
)
#region - Azure KeyVault Parameters
$kVSecretParameters = @{}
if($KeyVaultName -ne $null)
{
$kVSecretParameters.Add("Secret--KeyVault--Vault", $($KeyVaultName))
}
else
{
write-output "Key--KeyVault--Vault: NULL"
}
#endregion
#region - Set Azure KeyVault Secret
$kVSecretParameters.Keys | ForEach-Object {
$key = $_
$value = $kVSecretParameters.Item($_)
$Parameters = @{
VaultName = $KeyVaultName
}
if (Get-AzureKeyVaultSecret @Parameters | Where-Object { $psitem.Name -eq "$key" })
{
Write-Output "The secret for $key already exists"
}
else
{
Write-Output "Setting Secret for $key"
$Parameters = @{
VaultName = $KeyVaultName
Name = $key
SecretValue = (ConvertTo-SecureString $value -AsPlainText -Force)
}
Set-AzureKeyVaultSecret @Parameters -Verbose
}
}
#endregion

Просмотреть файл

@ -0,0 +1,159 @@
<#
.NOTES
==============================================================================================
Copyright(c) Microsoft Corporation. All rights reserved.
File: module.tests.ps1
Purpose: Pester - Test Key Vault ARM Templates
Version: 1.0.0.0 - 1st April 2019 - Azure Virtual Datacenter Development Team
==============================================================================================
.SYNOPSIS
This script contains functionality used to test Key Vault ARM template synatax.
.DESCRIPTION
This script contains functionality used to test Key Vault ARM template synatax.
Deployment steps of the script are outlined below.
1) Test Template File Syntax
2) Test Parameter File Syntax
3) Test Template and Parameter File Compactibility
#>
#Requires -Version 5
#region Parameters
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$here = Join-Path $here ".."
$template = Split-Path -Leaf $here
$TemplateFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "deploy.json") -Recurse | Select-Object -ExpandProperty Name) ) {
$TemplateFileTestCases += @{ TemplateFile = $File }
}
$ParameterFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "Tests" -AdditionalChildPath @("*parameters.json")) -Recurse -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Name) ) {
$ParameterFileTestCases += @{ ParameterFile = Join-Path "Tests" $File }
}
$Modules = @();
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "deploy.json") ) ) {
$Module = [PSCustomObject]@{
'Template' = $null
'Parameters' = $null
}
$Module.Template = $File.FullName;
$Parameters = @();
ForEach ( $ParameterFile in (Get-ChildItem (Join-Path "$here" "Tests" -AdditionalChildPath @("*parameters.json")) -Recurse -ErrorAction SilentlyContinue| Select-Object -ExpandProperty Name) ) {
$Parameters += (Join-Path "$here" "Tests" -AdditionalChildPath @("$ParameterFile") )
}
$Module.Parameters = $Parameters;
$Modules += @{ Module = $Module };
}
#endregion
#region Run Pester Test Script
Describe "Template: $template - Key Vault" -Tags Unit {
Context "Template File Syntax" {
It "Has a JSON template file" {
(Join-Path "$here" "deploy.json") | Should Exist
}
It "Converts from JSON and has the expected properties" -TestCases $TemplateFileTestCases {
Param( $TemplateFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters',
'variables',
'resources',
'outputs' | Sort-Object
$templateProperties = (Get-Content (Join-Path "$here" "$TemplateFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateProperties | Should Be $expectedProperties
}
}
Context "Parameter File Syntax" {
It "Parameter file does not contains the expected properties" -TestCases $ParameterFileTestCases {
Param( $ParameterFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters' | Sort-Object
Write-Host $ParameterFile
Join-Path "$here" "$ParameterFile" | Write-Host
$templateFileProperties = (Get-Content (Join-Path "$here" "$ParameterFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateFileProperties | Should Be $expectedProperties
}
}
Context "Template and Parameter Compactibility" {
It "Is count of required parameters in template file equal or lesser than count of all parameters in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$requiredParametersInTemplateFile.Count | Should Not BeGreaterThan $allParametersInParametersFile.Count;
}
}
It "Has all parameters in parameters file existing in template file" -TestCases $Modules {
Param( $Module )
$allParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
Write-Host "File analyzed: $Parameter";
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$result = @($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_});
Write-Host "Invalid parameters: $(ConvertTo-Json $result)";
@($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_}).Count | Should Be 0;
}
}
It "Has required parameters in template file existing in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
@($requiredParametersInTemplateFile| Where-Object {$allParametersInParametersFile -notcontains $_}).Count | Should Be 0;
}
}
}
}
#endregion

Просмотреть файл

@ -0,0 +1,47 @@
<#
.NOTES
==============================================================================================
Copyright(c) Microsoft Corporation. All rights reserved.
File: output.test.ps1
Purpose: Test - Key Vault ARM Template Output Variables
Version: 1.0.0.0 - 1st April 2019 - Azure Virtual Datacenter Development Team
==============================================================================================
.SYNOPSIS
This script contains functionality used to test Key Vault ARM template output variables.
.DESCRIPTION
This script contains functionality used to test Key Vault ARM template output variables.
Deployment steps of the script are outlined below.
1) Outputs Variable Logic to pipeline
.PARAMETER KeyVaultName
Specify the Key Vault Name output parameter.
.EXAMPLE
Default:
C:\PS>.\output.test.ps1 `
-KeyVaultName <"KeyVaultName">
#>
#Requires -Version 5
[CmdletBinding()]
param
(
[Parameter(Mandatory = $false)]
[string]$KeyVaultName
)
if($KeyVaultName -ne $null)
{
write-output "Azure Key Vault Name: $($KeyVaultName)"
}
else
{
write-output "Azure Key Vault Name: NULL"
}

Просмотреть файл

@ -0,0 +1,163 @@
<#
.NOTES
==============================================================================================
Copyright(c) Microsoft Corporation. All rights reserved.
File: module.tests.ps1
Purpose: Pester - Test Key Vault ARM Templates
Version: 1.0.0.0 - 1st April 2019 - Azure Virtual Datacenter Development Team
==============================================================================================
.SYNOPSIS
This script contains functionality used to test Azure Key Vault ARM template synatax.
.DESCRIPTION
This script contains functionality used to test Azure Key Vault ARM template synatax.
Deployment steps of the script are outlined below.
1) Test Template File Syntax
2) Test Parameter File Syntax
3) Test Template and Parameter File Compactibility
#>
#Requires -Version 5
#region Parameters
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$here = Join-Path $here ".."
$template = Split-Path -Leaf $here
$TemplateFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "Policy" -AdditionalChildPath @("deploy.json")) -Recurse -ErrorAction SilentlyContinue| Select-Object -ExpandProperty Name) ) {
$TemplateFileTestCases += @{ TemplateFile = $File }
}
$ParameterFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "Policy" -AdditionalChildPath @("*parameters.json")) -Recurse -ErrorAction SilentlyContinue| Select-Object -ExpandProperty Name) ) {
$ParameterFileTestCases += @{ ParameterFile = Join-Path "Policy" $File }
}
$Modules = @();
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "Policy" -AdditionalChildPath @("deploy.json")) -ErrorAction SilentlyContinue ) ) {
$Module = [PSCustomObject]@{
'Template' = $null
'Parameters' = $null
}
$Module.Template = $File.FullName;
$Parameters = @();
ForEach ( $ParameterFile in (Get-ChildItem (Join-Path "$here" "Policy" -AdditionalChildPath @("*parameters.json")) -Recurse -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Name) ) {
$Parameters += (Join-Path "$here" "Policy" -AdditionalChildPath @("$ParameterFile") )
}
$Module.Parameters = $Parameters;
$Modules += @{ Module = $Module };
}
#endregion
if ($null -ne $TemplateFileTestCases -and
$TemplateFileTestCases.Count -gt 0) {
#region Run Pester Test Script
Describe "Template: $template - Key Vault" -Tags Unit {
Context "Template File Syntax" {
It "Has a JSON template file" {
(Join-Path "$here" "deploy.json") | Should Exist
}
It "Converts from JSON and has the expected properties" -TestCases $TemplateFileTestCases {
Param( $TemplateFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters',
'variables',
'resources',
'outputs' | Sort-Object
$templateProperties = (Get-Content (Join-Path "$here" "$TemplateFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateProperties | Should Be $expectedProperties
}
}
Context "Parameter File Syntax" {
It "Parameter file does not contains the expected properties" -TestCases $ParameterFileTestCases {
Param( $ParameterFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters' | Sort-Object
Write-Host $ParameterFile
Join-Path "$here" "$ParameterFile" | Write-Host
$templateFileProperties = (Get-Content (Join-Path "$here" "$ParameterFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateFileProperties | Should Be $expectedProperties
}
}
Context "Template and Parameter Compactibility" {
It "Is count of required parameters in template file equal or lesser than count of all parameters in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$requiredParametersInTemplateFile.Count | Should Not BeGreaterThan $allParametersInParametersFile.Count;
}
}
It "Has all parameters in parameters file existing in template file" -TestCases $Modules {
Param( $Module )
$allParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
Write-Host "File analyzed: $Parameter";
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$result = @($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_});
Write-Host "Invalid parameters: $(ConvertTo-Json $result)";
@($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_}).Count | Should Be 0;
}
}
It "Has required parameters in template file existing in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
@($requiredParametersInTemplateFile| Where-Object {$allParametersInParametersFile -notcontains $_}).Count | Should Be 0;
}
}
}
}
#endregion
}

Просмотреть файл

@ -0,0 +1,163 @@
<#
.NOTES
==============================================================================================
Copyright(c) Microsoft Corporation. All rights reserved.
File: module.tests.ps1
Purpose: Pester - Test Key Vault ARM Templates
Version: 1.0.0.0 - 1st April 2019 - Azure Virtual Datacenter Development Team
==============================================================================================
.SYNOPSIS
This script contains functionality used to test Azure Key Vault ARM template synatax.
.DESCRIPTION
This script contains functionality used to test Azure Key Vault ARM template synatax.
Deployment steps of the script are outlined below.
1) Test Template File Syntax
2) Test Parameter File Syntax
3) Test Template and Parameter File Compactibility
#>
#Requires -Version 5
#region Parameters
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$here = Join-Path $here ".."
$template = Split-Path -Leaf $here
$TemplateFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "RBAC" -AdditionalChildPath @("deploy.json")) -ErrorAction SilentlyContinue -Recurse | Select-Object -ExpandProperty Name) ) {
$TemplateFileTestCases += @{ TemplateFile = $File }
}
$ParameterFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "RBAC" -AdditionalChildPath @("*parameters.json")) -ErrorAction SilentlyContinue -Recurse | Select-Object -ExpandProperty Name) ) {
$ParameterFileTestCases += @{ ParameterFile = Join-Path "RBAC" $File }
}
$Modules = @();
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "RBAC" -AdditionalChildPath @("deploy.json")) -ErrorAction SilentlyContinue ) ) {
$Module = [PSCustomObject]@{
'Template' = $null
'Parameters' = $null
}
$Module.Template = $File.FullName;
$Parameters = @();
ForEach ( $ParameterFile in (Get-ChildItem (Join-Path "$here" "RBAC" -AdditionalChildPath @("*parameters.json")) -Recurse | Select-Object -ExpandProperty Name) ) {
$Parameters += (Join-Path "$here" "RBAC" -AdditionalChildPath @("$ParameterFile") )
}
$Module.Parameters = $Parameters;
$Modules += @{ Module = $Module };
}
#endregion
if ($null -ne $TemplateFileTestCases -and
$TemplateFileTestCases.Count -gt 0) {
#region Run Pester Test Script
Describe "Template: $template - Key Vault" -Tags Unit {
Context "Template File Syntax" {
It "Has a JSON template file" -TestCases $TemplateFileTestCases {
(Join-Path "$here" "deploy.json") | Should Exist
}
It "Converts from JSON and has the expected properties" -TestCases $TemplateFileTestCases {
Param( $TemplateFile )
Write-Host "TF: $TemplateFile"
$expectedProperties = '$schema',
'contentVersion',
'parameters',
'variables',
'resources',
'outputs' | Sort-Object
$templateProperties = (Get-Content (Join-Path "$here" "$TemplateFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateProperties | Should Be $expectedProperties
}
}
Context "Parameter File Syntax" {
It "Parameter file does not contains the expected properties" -TestCases $ParameterFileTestCases {
Param( $ParameterFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters' | Sort-Object
Write-Host $ParameterFile
Join-Path "$here" "$ParameterFile" | Write-Host
$templateFileProperties = (Get-Content (Join-Path "$here" "$ParameterFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateFileProperties | Should Be $expectedProperties
}
}
Context "Template and Parameter Compactibility" {
It "Is count of required parameters in template file equal or lesser than count of all parameters in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$requiredParametersInTemplateFile.Count | Should Not BeGreaterThan $allParametersInParametersFile.Count;
}
}
It "Has all parameters in parameters file existing in template file" -TestCases $Modules {
Param( $Module )
$allParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
Write-Host "File analyzed: $Parameter";
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$result = @($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_});
Write-Host "Invalid parameters: $(ConvertTo-Json $result)";
@($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_}).Count | Should Be 0;
}
}
It "Has required parameters in template file existing in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
@($requiredParametersInTemplateFile| Where-Object {$allParametersInParametersFile -notcontains $_}).Count | Should Be 0;
}
}
}
}
#endregion
}

Просмотреть файл

@ -0,0 +1,15 @@
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"virtualMachineName": {
"value": "foo"
},
"artifactsStorageAccountName": {
"value": "contoso"
},
"artifactsStorageAccountSasKey": {
"value": "somekey"
}
}
}

Просмотреть файл

@ -0,0 +1,15 @@
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"virtualMachineScaleSetsName": {
"value": "foo"
},
"artifactsStorageAccountName": {
"value": "contoso"
},
"artifactsStorageAccountSasKey": {
"value": "somekey"
}
}
}

Просмотреть файл

@ -0,0 +1,118 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"virtualMachineName": {
"type": "string",
"defaultValue": "",
"maxLength": 13,
"metadata": {
"description": "Optional. Name for the VMs. Required if virtualMachineScaleSetsName is empty"
}
},
"virtualMachineCount": {
"type": "int",
"defaultValue": 1,
"metadata": {
"description": "Optional. Number of VMs to create"
}
},
"virtualMachineOffset": {
"type": "int",
"defaultValue": 1,
"metadata": {
"description": "Optional. This value will be used as start VM count. Specify a value if you want to create VMs starting at a specific number, this is useful when you want to append more VMs."
}
},
"virtualMachineScaleSetsName": {
"type": "string",
"defaultValue": "",
"maxLength": 13,
"metadata": {
"description": "Optional. Name for VMSS. Required if virtualMachineName is empty"
}
},
"artifactsStorageAccountName": {
"type": "securestring",
"metadata": {
"description": "Required. Default storage account name. Storage account that contains output parameters and common scripts"
}
},
"artifactsStorageAccountSasKey": {
"type": "securestring",
"metadata": {
"description": "Required. Shared Access Signature Key used to download custom scripts"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Optional. Location for all resources."
}
}
},
"variables": {
"isVMSS": "[not(empty(parameters('virtualMachineScaleSetsName')))]",
"DSCExtensionName": "DSCExtension",
"artifactsStorageAccountSasToken": "[concat('?', parameters('artifactsStorageAccountSasKey'))]"
},
"resources": [
{
"apiVersion": "2019-03-01",
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "[concat(parameters('virtualMachineName'), copyindex(parameters('virtualMachineOffset')), '/', variables('DSCExtensionName'))]",
"condition": "[not(variables('isVMSS'))]",
"location": "[parameters('location')]",
"copy": {
"name": "vmInstallIIS",
"count": "[parameters('virtualMachineCount')]"
},
"properties": {
"publisher": "Microsoft.Powershell",
"type": "DSC",
"typeHandlerVersion": "2.9",
"autoUpgradeMinorVersion": true,
"settings": {
"configuration": {
"url": "[concat('https://', parameters('artifactsStorageAccountName'), '.blob.core.windows.net/scripts/Windows/iisaspnet.zip')]",
"script": "iisaspnet.ps1",
"function": "IISASPNET"
}
},
"protectedSettings": {
"configurationUrlSasToken": "[variables('artifactsStorageAccountSasToken')]"
}
}
},
{
"type": "Microsoft.Compute/virtualMachineScaleSets/extensions",
"apiVersion": "2019-03-01",
"name": "[concat(parameters('virtualMachineScaleSetsName'), '/', variables('DSCExtensionName'))]",
"condition": "[variables('isVMSS')]",
"location": "[parameters('location')]",
"properties": {
"publisher": "Microsoft.Powershell",
"type": "DSC",
"typeHandlerVersion": "2.9",
"autoUpgradeMinorVersion": true,
"settings": {
"configuration": {
"url": "[concat('https://', parameters('artifactsStorageAccountName'), '.blob.core.windows.net/scripts/Windows/iisaspnet.zip')]",
"script": "iisaspnet.ps1",
"function": "IISASPNET"
}
},
"protectedSettings": {
"configurationUrlSasToken": "[variables('artifactsStorageAccountSasToken')]"
}
}
}
],
"outputs": {
"IISResourceGroup": {
"type": "string",
"value": "[resourceGroup().name]"
}
}
}

Просмотреть файл

@ -0,0 +1,44 @@
# KeyVault
This module deploys Key Vault.
## Resources
- Microsoft.KeyVault/vaults
- Microsoft.KeyVault/vaults/providers/diagnosticsettings
- Microsoft.KeyVault/vaults/secrets
## Parameters
| Parameter Name | Default Value | Description |
| :- | :- | :- |
| `keyVaultName` | | Required. Name of the Azure Key Vault
| `accessPolicies` | `{}` | Optional. Access policies object
| `secretsObject` | `{}` | Optional. All secrets {\"secretName\":\"\",\"secretValue\":\"\"} wrapped in a secure object
| `enableVaultForDeployment` | `true` | Optional. Specifies if the vault is enabled for deployment by script or compute
| `enableVaultForTemplateDeployment` | `true` | Optional. Specifies if the vault is enabled for a template deployment
| `enableVaultForDiskEncryption` | `true` | Optional. Specifies if the azure platform has access to the vault for enabling disk encryption scenarios.
| `logsRetentionInDays` | `365` | Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely.
| `vaultSku` | `Premium` | Optional. Specifies the SKU for the vault
| `diagnosticStorageAccountId` | | Required. Resource identifier of the Diagnostic Storage Account.
| `workspaceId` | | Required. Resource identifier of Log Analytics.
| `networkAcls` | | Required. Service endpoint object information
| `vNetId` | | Required. Virtual Network resource identifier
## Outputs
| Output Name | Description |
| :- | :- |
| `keyVaultResourceId` | The Resource Id of the Key Vault.
| `keyVaultResourceGroup` | The name of the Resource Group the Key Vault was created in.
| `keyVaultName` | The Name of the Key Vault.
| `keyVaultUrl` | The Name of the Key Vault.
## Considerations
*N/A*
## Additional resources
- [What is Azure Key Vault?](https://docs.microsoft.com/en-us/azure/key-vault/key-vault-whatis)
- [Microsoft.KeyVault vaults template reference](https://docs.microsoft.com/en-us/azure/templates/microsoft.keyvault/2018-02-14/vaults)

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,72 +0,0 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"windowsVirtualMachineName": {
"value": "winjb"
},
"linuxVirtualMachineName": {
"value": "linuxjb"
},
"workspaceId": {
"value": ""
},
"logAnalyticsWorkspacePrimarySharedKey": {
"value": ""
},
"artifactsStorageAccountKey": {
"value": ""
},
"artifactsStorageAccountName": {
"value": ""
},
"vNetId": {
"value": ""
},
"jumpboxAsgId": {
"value": ""
},
"subnetName": {
"value": ""
},
"adminUsername": {
"value": ""
},
"adminPassword": {
"value": ""
},
"windowsVirtualMachineCount": {
"value": 1
},
"windowsVirtualMachineSize": {
"value": "Standard_DS2_v2"
},
"windowsOSImage": {
"value": {
"offer": "WindowsServer",
"publisher": "MicrosoftWindowsServer",
"sku": "2016-Datacenter"
}
},
"linuxVirtualMachineCount": {
"value": 1
},
"linuxVirtualMachineSize": {
"value": "Standard_D2s_v3"
},
"linuxOSImage": {
"value": {
"publisher": "Canonical",
"offer": "UbuntuServer",
"sku": "18.04-LTS",
"version": "latest"
}
},
"diagnosticsStorageAccountName": {
"value": ""
},
"diagnosticsStorageAccountSasToken": {
"value": ""
}
}
}

Просмотреть файл

@ -1,52 +0,0 @@
# Jumpbox
This template deploys a Jumpbox.
## Resources
- Microsoft.Compute/virtualMachines
- Microsoft.Compute/availabilitySets
- Microsoft.Network/networkInterfaces
- Microsoft.Compute/virtualMachines/extensions
- Microsoft.Compute/virtualMachines/providers/guestConfigurationAssignments
## Parameters
| Parameter Name | Default Value | Description |
| :- | :- | :- |
| `windowsVirtualMachineName` | | Required. Name for the Jumpbox VM
| `linuxVirtualMachineName` | | Required. Name for the Jumpbox VM
| `workspaceId` | | Required. CustomerId value of Log Analytics. This value is referenced in MMA Extension
| `logAnalyticsWorkspacePrimarySharedKey` | | Required. WorkspaceKey value of OMS. This value is referenced in OMS VM Extension
| `artifactsStorageAccountKey` | | Required. Artifacts storage account Key. Storage account that contains output parameters and common scripts
| `artifactsStorageAccountName` | | Required. Artifacts storage account Name.
| `keyVaultURL` | `""` | Optional. AKV URI
| `keyVaultId` | `""` | Optional. AKV Resource Id
| `jumpboxKeyEncryptionURL` | `""` | Optional. Jumpbox AKV encryption key
| `vNetId` | | Required. Shared services Virtual Network resource Id
| `jumpboxAsgId` | | Required. Jumpbox ASG resource identifier
| `subnetName` | | Required. Name of Shared Services Subnet, this name is used to get the SubnetId
| `adminUserName` | | Required. The username used to establish jumpbox VMs.
| `adminPassword` | | Required. The password given to the admin user.
| `windowsVirtualMachineCount` | `1` | Optional. Number of jumpbox VMs to be created.
| `windowsVirtualMachineSize` | | Required. Size of the jumpbox VMs.
| `windowsOSImage` | | Required. OS image used for the jumpbox VMs.
| `linuxVirtualMachineCount` | `1` | Optional. Number of linux jumpbox VMs to be created.
| `linuxVirtualMachineSize` | | Required. Size of the jumpbox VMs.
| `linuxOSImage` | | Required. OS image used for the jumpbox VMs.
| `diagnosticsStorageAccountName` | | Required. Diagnostic Storage Account name
| `diagnosticsStorageAccountSasToken` | | Required. Diagnostic Storage Account SAS token
## Outputs
*N/A*
## Considerations
*N/A*
## Additional resources
- [Microsoft.Compute virtualMachines template reference](https://docs.microsoft.com/en-us/azure/templates/microsoft.compute/2019-03-01/virtualmachines)
- [Microsoft.Compute availabilitySets template reference)[https://docs.microsoft.com/en-us/azure/templates/microsoft.compute/2019-03-01/availabilitysets]
- [Microsoft.Network networkInterfaces template reference](https://docs.microsoft.com/en-us/azure/templates/microsoft.network/2018-11-01/networkinterfaces)

Просмотреть файл

@ -0,0 +1,161 @@
<#
.NOTES
==============================================================================================
Copyright(c) Microsoft Corporation. All rights reserved.
File: module.tests.ps1
Purpose: Pester - Test Load Balancers ARM Templates
Version: 1.0.0.0 - 1st April 2019 - Azure Virtual Datacenter Development Team
==============================================================================================
.SYNOPSIS
This script contains functionality used to test Load Balancers ARM template synatax.
.DESCRIPTION
This script contains functionality used to test Load Balancers ARM template synatax.
Deployment steps of the script are outlined below.
1) Test Template File Syntax
2) Test Parameter File Syntax
3) Test Template and Parameter File Compactibility
#>
#Requires -Version 5
#region Parameters
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$here = Join-Path $here ".."
$template = Split-Path -Leaf $here
$TemplateFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "deploy.json") -Recurse | Select-Object -ExpandProperty Name) ) {
$TemplateFileTestCases += @{ TemplateFile = $File }
}
$ParameterFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "Tests" -AdditionalChildPath @("*parameters.json")) -Recurse -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Name) ) {
$ParameterFileTestCases += @{ ParameterFile = Join-Path "Tests" $File }
}
$Modules = @();
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "deploy.json") ) ) {
$Module = [PSCustomObject]@{
'Template' = $null
'Parameters' = $null
}
$Module.Template = $File.FullName;
$Parameters = @();
ForEach ( $ParameterFile in (Get-ChildItem (Join-Path "$here" "Tests" -AdditionalChildPath @("*parameters.json")) -Recurse -ErrorAction SilentlyContinue| Select-Object -ExpandProperty Name) ) {
$Parameters += (Join-Path "$here" "Tests" -AdditionalChildPath @("$ParameterFile") )
}
$Module.Parameters = $Parameters;
$Modules += @{ Module = $Module };
}
#endregion
#region Run Pester Test Script
Describe "Template: $template - Load Balancers" -Tags Unit {
Context "Template File Syntax" {
It "Has a JSON template file" {
(Join-Path "$here" "deploy.json") | Should Exist
}
It "Converts from JSON and has the expected properties" -TestCases $TemplateFileTestCases {
Param( $TemplateFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters',
'variables',
'resources',
'outputs' | Sort-Object
$templateProperties = (Get-Content (Join-Path "$here" "$TemplateFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateProperties | Should Be $expectedProperties
}
}
Context "Parameter File Syntax" {
It "Parameter file does not contains the expected properties" -TestCases $ParameterFileTestCases {
Param( $ParameterFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters' | Sort-Object
Write-Host $ParameterFile
Join-Path "$here" "$ParameterFile" | Write-Host
$templateFileProperties = (Get-Content (Join-Path "$here" "$ParameterFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateFileProperties | Should Be $expectedProperties
}
}
Context "Template and Parameter Compactibility" {
It "Is count of required parameters in template file equal or lesser than count of all parameters in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$requiredParametersInTemplateFile.Count | Should Not BeGreaterThan $allParametersInParametersFile.Count;
}
}
It "Has all parameters in parameters file existing in template file" -TestCases $Modules {
Param( $Module )
$allParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
Write-Host "File analyzed: $Parameter";
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$result = @($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_});
Write-Host "Invalid parameters: $(ConvertTo-Json $result)";
@($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_}).Count | Should Be 0;
}
}
It "Has required parameters in template file existing in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
@($requiredParametersInTemplateFile | Where-Object {$allParametersInParametersFile -notcontains $_}).Count | Should Be 0;
}
}
}
}
#endregion

Просмотреть файл

@ -0,0 +1,47 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"loadBalancerName": {
"value": "contoso-lb"
},
"loadBalancingRules": {
"value": [
{
"name": "load-balancing-1",
"properties": {
"frontendPort": 80,
"backendPort": 80,
"enableFloatingIP": false,
"idleTimeoutInMinutes": 3,
"protocol": "TCP",
"enableTcpReset": false,
"loadDistribution": false,
"disableOutboundSnat": false,
"probeName": "bar"
}
}
]
},
"probes": {
"value": [
{
"name": "probe",
"properties": {
"protocol": "TCP",
"port": 80,
"requestPath": "/",
"intervalInSeconds": 10,
"numberOfProbes": 5
}
}
]
},
"vNetId": {
"value": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourceGroup/providers/Microsoft.Network/virtualNetworks/contoso-vnet-example"
},
"subnetName": {
"value": "sharedsvcs"
}
}
}

Просмотреть файл

@ -0,0 +1,163 @@
<#
.NOTES
==============================================================================================
Copyright(c) Microsoft Corporation. All rights reserved.
File: module.tests.ps1
Purpose: Pester - Test Virtual Machine ARM Templates
Version: 1.0.0.0 - 1st April 2019 - Azure Virtual Datacenter Development Team
==============================================================================================
.SYNOPSIS
This script contains functionality used to test Azure Virtual Machine ARM template synatax.
.DESCRIPTION
This script contains functionality used to test Azure Virtual Machine ARM template synatax.
Deployment steps of the script are outlined below.
1) Test Template File Syntax
2) Test Parameter File Syntax
3) Test Template and Parameter File Compactibility
#>
#Requires -Version 5
#region Parameters
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$here = Join-Path $here ".."
$template = Split-Path -Leaf $here
$TemplateFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "Policy" -AdditionalChildPath @("deploy.json")) -Recurse -ErrorAction SilentlyContinue| Select-Object -ExpandProperty Name) ) {
$TemplateFileTestCases += @{ TemplateFile = $File }
}
$ParameterFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "Policy" -AdditionalChildPath @("*parameters.json")) -Recurse -ErrorAction SilentlyContinue| Select-Object -ExpandProperty Name) ) {
$ParameterFileTestCases += @{ ParameterFile = Join-Path "Policy" $File }
}
$Modules = @();
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "Policy" -AdditionalChildPath @("deploy.json")) -ErrorAction SilentlyContinue ) ) {
$Module = [PSCustomObject]@{
'Template' = $null
'Parameters' = $null
}
$Module.Template = $File.FullName;
$Parameters = @();
ForEach ( $ParameterFile in (Get-ChildItem (Join-Path "$here" "Policy" -AdditionalChildPath @("*parameters.json")) -Recurse -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Name) ) {
$Parameters += (Join-Path "$here" "Policy" -AdditionalChildPath @("$ParameterFile") )
}
$Module.Parameters = $Parameters;
$Modules += @{ Module = $Module };
}
#endregion
if ($null -ne $TemplateFileTestCases -and
$TemplateFileTestCases.Count -gt 0) {
#region Run Pester Test Script
Describe "Template: $template - Virtual Machine" -Tags Unit {
Context "Template File Syntax" {
It "Has a JSON template file" {
(Join-Path "$here" "deploy.json") | Should Exist
}
It "Converts from JSON and has the expected properties" -TestCases $TemplateFileTestCases {
Param( $TemplateFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters',
'variables',
'resources',
'outputs' | Sort-Object
$templateProperties = (Get-Content (Join-Path "$here" "$TemplateFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateProperties | Should Be $expectedProperties
}
}
Context "Parameter File Syntax" {
It "Parameter file does not contains the expected properties" -TestCases $ParameterFileTestCases {
Param( $ParameterFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters' | Sort-Object
Write-Host $ParameterFile
Join-Path "$here" "$ParameterFile" | Write-Host
$templateFileProperties = (Get-Content (Join-Path "$here" "$ParameterFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateFileProperties | Should Be $expectedProperties
}
}
Context "Template and Parameter Compactibility" {
It "Is count of required parameters in template file equal or lesser than count of all parameters in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$requiredParametersInTemplateFile.Count | Should Not BeGreaterThan $allParametersInParametersFile.Count;
}
}
It "Has all parameters in parameters file existing in template file" -TestCases $Modules {
Param( $Module )
$allParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
Write-Host "File analyzed: $Parameter";
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$result = @($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_});
Write-Host "Invalid parameters: $(ConvertTo-Json $result)";
@($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_}).Count | Should Be 0;
}
}
It "Has required parameters in template file existing in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
@($requiredParametersInTemplateFile| Where-Object {$allParametersInParametersFile -notcontains $_}).Count | Should Be 0;
}
}
}
}
#endregion
}

Просмотреть файл

@ -0,0 +1,163 @@
<#
.NOTES
==============================================================================================
Copyright(c) Microsoft Corporation. All rights reserved.
File: module.tests.ps1
Purpose: Pester - Test Virtual Machine ARM Templates
Version: 1.0.0.0 - 1st April 2019 - Azure Virtual Datacenter Development Team
==============================================================================================
.SYNOPSIS
This script contains functionality used to test Azure Virtual Machine ARM template synatax.
.DESCRIPTION
This script contains functionality used to test Azure Virtual Machine ARM template synatax.
Deployment steps of the script are outlined below.
1) Test Template File Syntax
2) Test Parameter File Syntax
3) Test Template and Parameter File Compactibility
#>
#Requires -Version 5
#region Parameters
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$here = Join-Path $here ".."
$template = Split-Path -Leaf $here
$TemplateFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "RBAC" -AdditionalChildPath @("deploy.json")) -ErrorAction SilentlyContinue -Recurse | Select-Object -ExpandProperty Name) ) {
$TemplateFileTestCases += @{ TemplateFile = $File }
}
$ParameterFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "RBAC" -AdditionalChildPath @("*parameters.json")) -ErrorAction SilentlyContinue -Recurse | Select-Object -ExpandProperty Name) ) {
$ParameterFileTestCases += @{ ParameterFile = Join-Path "RBAC" $File }
}
$Modules = @();
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "RBAC" -AdditionalChildPath @("deploy.json")) -ErrorAction SilentlyContinue ) ) {
$Module = [PSCustomObject]@{
'Template' = $null
'Parameters' = $null
}
$Module.Template = $File.FullName;
$Parameters = @();
ForEach ( $ParameterFile in (Get-ChildItem (Join-Path "$here" "RBAC" -AdditionalChildPath @("*parameters.json")) -Recurse | Select-Object -ExpandProperty Name) ) {
$Parameters += (Join-Path "$here" "RBAC" -AdditionalChildPath @("$ParameterFile") )
}
$Module.Parameters = $Parameters;
$Modules += @{ Module = $Module };
}
#endregion
if ($null -ne $TemplateFileTestCases -and
$TemplateFileTestCases.Count -gt 0) {
#region Run Pester Test Script
Describe "Template: $template - Virtual Machine" -Tags Unit {
Context "Template File Syntax" {
It "Has a JSON template file" -TestCases $TemplateFileTestCases {
(Join-Path "$here" "deploy.json") | Should Exist
}
It "Converts from JSON and has the expected properties" -TestCases $TemplateFileTestCases {
Param( $TemplateFile )
Write-Host "TF: $TemplateFile"
$expectedProperties = '$schema',
'contentVersion',
'parameters',
'variables',
'resources',
'outputs' | Sort-Object
$templateProperties = (Get-Content (Join-Path "$here" "$TemplateFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateProperties | Should Be $expectedProperties
}
}
Context "Parameter File Syntax" {
It "Parameter file does not contains the expected properties" -TestCases $ParameterFileTestCases {
Param( $ParameterFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters' | Sort-Object
Write-Host $ParameterFile
Join-Path "$here" "$ParameterFile" | Write-Host
$templateFileProperties = (Get-Content (Join-Path "$here" "$ParameterFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateFileProperties | Should Be $expectedProperties
}
}
Context "Template and Parameter Compactibility" {
It "Is count of required parameters in template file equal or lesser than count of all parameters in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$requiredParametersInTemplateFile.Count | Should Not BeGreaterThan $allParametersInParametersFile.Count;
}
}
It "Has all parameters in parameters file existing in template file" -TestCases $Modules {
Param( $Module )
$allParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
Write-Host "File analyzed: $Parameter";
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$result = @($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_});
Write-Host "Invalid parameters: $(ConvertTo-Json $result)";
@($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_}).Count | Should Be 0;
}
}
It "Has required parameters in template file existing in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
@($requiredParametersInTemplateFile| Where-Object {$allParametersInParametersFile -notcontains $_}).Count | Should Be 0;
}
}
}
}
#endregion
}

Просмотреть файл

@ -0,0 +1,157 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"loadBalancerName": {
"type": "string",
"metadata": {
"description": "Required. The Proximity Placement Groups Name"
}
},
"loadBalancingRules": {
"type": "array",
"minLength": 1,
"metadata": {
"description": "Required. Array of objects containing all load balancing rules"
}
},
"probes": {
"type": "array",
"minLength": 1,
"metadata": {
"description": "Required. Array of objects containing all probes, these are references in the load balancing rules"
}
},
"vNetId": {
"type": "string",
"metadata": {
"description": "Required. Shared services Virtual Network resource identifier"
}
},
"subnetName": {
"type": "string",
"metadata": {
"description": "Required. Name of Shared Services Subnet, this name is used to get the SubnetId"
}
},
"loadBalancerIPAddress": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Optional. IP address statically assigned to the Load Balancer. If left empty, the Load Balancer will use the next available IP (dynamic assignment)"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Optional. Location for all resources."
}
}
},
"variables": {
"subnetId": "[concat(parameters('vNetId'), '/subnets/', parameters('subnetName'))]",
"frontendIPConfiguration": "[concat(parameters('loadBalancerName'), '-fe')]",
"loadBalancerBackendPoolName": "[concat(parameters('loadBalancerName'), '-bp')]",
"loadBalancingRules": {
"copy": [
{
"name": "loadBalancingRules",
"count": "[length(parameters('loadBalancingRules'))]",
"input": {
"name": "[parameters('loadBalancingRules')[copyIndex('loadBalancingRules')].name]",
"properties": {
"frontendIPConfiguration": {
"id": "[resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('loadBalancerName'), variables('frontendIPConfiguration'))]"
},
"backendAddressPool": {
"id": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('loadBalancerName'), variables('loadBalancerBackendPoolName'))]"
},
"frontendPort": "[parameters('loadBalancingRules')[copyIndex('loadBalancingRules')].properties.frontendPort]",
"backendPort": "[parameters('loadBalancingRules')[copyIndex('loadBalancingRules')].properties.backendPort]",
"enableFloatingIP": "[parameters('loadBalancingRules')[copyIndex('loadBalancingRules')].properties.enableFloatingIP]",
"idleTimeoutInMinutes": "[parameters('loadBalancingRules')[copyIndex('loadBalancingRules')].properties.idleTimeoutInMinutes]",
"protocol": "[parameters('loadBalancingRules')[copyIndex('loadBalancingRules')].properties.protocol]",
"enableTcpReset": "[parameters('loadBalancingRules')[copyIndex('loadBalancingRules')].properties.enableTcpReset]",
"loadDistribution": "[parameters('loadBalancingRules')[copyIndex('loadBalancingRules')].properties.loadDistribution]",
"disableOutboundSnat": "[parameters('loadBalancingRules')[copyIndex('loadBalancingRules')].properties.disableOutboundSnat]",
"probe": {
"id": "[resourceId('Microsoft.Network/loadBalancers/probes', parameters('loadBalancerName'), parameters('loadBalancingRules')[copyIndex('loadBalancingRules')].properties.probeName)]"
}
}
}
}
]
},
"probes": {
"copy": [
{
"name": "probes",
"count": "[length(parameters('probes'))]",
"input": {
"name": "[parameters('probes')[copyIndex('probes')].name]",
"properties": {
"protocol": "[parameters('probes')[copyIndex('probes')].properties.protocol]",
"port": "[parameters('probes')[copyIndex('probes')].properties.port]",
"requestPath": "[parameters('probes')[copyIndex('probes')].properties.requestPath]",
"intervalInSeconds": "[parameters('probes')[copyIndex('probes')].properties.intervalInSeconds]",
"numberOfProbes": "[parameters('probes')[copyIndex('probes')].properties.numberOfProbes]"
}
}
}
]
}
},
"resources": [
{
"name": "[parameters('loadBalancerName')]",
"type": "Microsoft.Network/loadBalancers",
"apiVersion": "2019-04-01",
"location": "[parameters('location')]",
"tags": {},
"sku": {
"name": "Standard"
},
"properties": {
"frontendIPConfigurations": [
{
"name": "[variables('frontendIPConfiguration')]",
"properties": {
"subnet": {
"id": "[variables('subnetId')]"
},
"privateIPAddress": "[if(empty(parameters('loadBalancerIPAddress')), json('null'), parameters('loadBalancerIPAddress'))]",
"privateIPAllocationMethod": "[if(empty(parameters('loadBalancerIPAddress')), 'Dynamic', 'Static')]"
}
}
],
"backendAddressPools": [
{
"name": "[variables('loadBalancerBackendPoolName')]"
}
],
"loadBalancingRules": "[variables('loadBalancingRules').loadBalancingRules]",
"probes": "[variables('probes').probes]"
},
"resources": []
}
],
"outputs": {
"loadBalancerName": {
"type": "string",
"value": "[parameters('loadBalancerName')]"
},
"loadBalancerResourceId": {
"type": "string",
"value": "[resourceId('Microsoft.Network/loadBalancers', parameters('loadBalancerName'))]"
},
"loadBalancerResourceGroup": {
"type": "string",
"value": "[resourceGroup().name]"
},
"loadBalancerResourceBackendPoolId": {
"type": "string",
"value": "[concat(resourceId('Microsoft.Network/loadBalancers', parameters('loadBalancerName')), '/backendAddressPools/', variables('loadBalancerBackendPoolName'))]"
}
}
}

Просмотреть файл

@ -0,0 +1,161 @@
<#
.NOTES
==============================================================================================
Copyright(c) Microsoft Corporation. All rights reserved.
File: module.tests.ps1
Purpose: Pester - Test Proximity Placement Groups ARM Templates
Version: 1.0.0.0 - 1st April 2019 - Azure Virtual Datacenter Development Team
==============================================================================================
.SYNOPSIS
This script contains functionality used to test Proximity Placement Groups ARM template synatax.
.DESCRIPTION
This script contains functionality used to test Proximity Placement Groups ARM template synatax.
Deployment steps of the script are outlined below.
1) Test Template File Syntax
2) Test Parameter File Syntax
3) Test Template and Parameter File Compactibility
#>
#Requires -Version 5
#region Parameters
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$here = Join-Path $here ".."
$template = Split-Path -Leaf $here
$TemplateFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "deploy.json") -Recurse | Select-Object -ExpandProperty Name) ) {
$TemplateFileTestCases += @{ TemplateFile = $File }
}
$ParameterFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "Tests" -AdditionalChildPath @("*parameters.json")) -Recurse -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Name) ) {
$ParameterFileTestCases += @{ ParameterFile = Join-Path "Tests" $File }
}
$Modules = @();
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "deploy.json") ) ) {
$Module = [PSCustomObject]@{
'Template' = $null
'Parameters' = $null
}
$Module.Template = $File.FullName;
$Parameters = @();
ForEach ( $ParameterFile in (Get-ChildItem (Join-Path "$here" "Tests" -AdditionalChildPath @("*parameters.json")) -Recurse -ErrorAction SilentlyContinue| Select-Object -ExpandProperty Name) ) {
$Parameters += (Join-Path "$here" "Tests" -AdditionalChildPath @("$ParameterFile") )
}
$Module.Parameters = $Parameters;
$Modules += @{ Module = $Module };
}
#endregion
#region Run Pester Test Script
Describe "Template: $template - Proximity Placement Groups" -Tags Unit {
Context "Template File Syntax" {
It "Has a JSON template file" {
(Join-Path "$here" "deploy.json") | Should Exist
}
It "Converts from JSON and has the expected properties" -TestCases $TemplateFileTestCases {
Param( $TemplateFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters',
'variables',
'resources',
'outputs' | Sort-Object
$templateProperties = (Get-Content (Join-Path "$here" "$TemplateFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateProperties | Should Be $expectedProperties
}
}
Context "Parameter File Syntax" {
It "Parameter file does not contains the expected properties" -TestCases $ParameterFileTestCases {
Param( $ParameterFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters' | Sort-Object
Write-Host $ParameterFile
Join-Path "$here" "$ParameterFile" | Write-Host
$templateFileProperties = (Get-Content (Join-Path "$here" "$ParameterFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateFileProperties | Should Be $expectedProperties
}
}
Context "Template and Parameter Compactibility" {
It "Is count of required parameters in template file equal or lesser than count of all parameters in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$requiredParametersInTemplateFile.Count | Should Not BeGreaterThan $allParametersInParametersFile.Count;
}
}
It "Has all parameters in parameters file existing in template file" -TestCases $Modules {
Param( $Module )
$allParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
Write-Host "File analyzed: $Parameter";
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$result = @($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_});
Write-Host "Invalid parameters: $(ConvertTo-Json $result)";
@($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_}).Count | Should Be 0;
}
}
It "Has required parameters in template file existing in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
@($requiredParametersInTemplateFile | Where-Object {$allParametersInParametersFile -notcontains $_}).Count | Should Be 0;
}
}
}
}
#endregion

Просмотреть файл

@ -0,0 +1,9 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"proximityPlacementGroupsName": {
"value": "foo"
}
}
}

Просмотреть файл

@ -0,0 +1,163 @@
<#
.NOTES
==============================================================================================
Copyright(c) Microsoft Corporation. All rights reserved.
File: module.tests.ps1
Purpose: Pester - Test Virtual Machine ARM Templates
Version: 1.0.0.0 - 1st April 2019 - Azure Virtual Datacenter Development Team
==============================================================================================
.SYNOPSIS
This script contains functionality used to test Azure Virtual Machine ARM template synatax.
.DESCRIPTION
This script contains functionality used to test Azure Virtual Machine ARM template synatax.
Deployment steps of the script are outlined below.
1) Test Template File Syntax
2) Test Parameter File Syntax
3) Test Template and Parameter File Compactibility
#>
#Requires -Version 5
#region Parameters
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$here = Join-Path $here ".."
$template = Split-Path -Leaf $here
$TemplateFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "Policy" -AdditionalChildPath @("deploy.json")) -Recurse -ErrorAction SilentlyContinue| Select-Object -ExpandProperty Name) ) {
$TemplateFileTestCases += @{ TemplateFile = $File }
}
$ParameterFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "Policy" -AdditionalChildPath @("*parameters.json")) -Recurse -ErrorAction SilentlyContinue| Select-Object -ExpandProperty Name) ) {
$ParameterFileTestCases += @{ ParameterFile = Join-Path "Policy" $File }
}
$Modules = @();
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "Policy" -AdditionalChildPath @("deploy.json")) -ErrorAction SilentlyContinue ) ) {
$Module = [PSCustomObject]@{
'Template' = $null
'Parameters' = $null
}
$Module.Template = $File.FullName;
$Parameters = @();
ForEach ( $ParameterFile in (Get-ChildItem (Join-Path "$here" "Policy" -AdditionalChildPath @("*parameters.json")) -Recurse -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Name) ) {
$Parameters += (Join-Path "$here" "Policy" -AdditionalChildPath @("$ParameterFile") )
}
$Module.Parameters = $Parameters;
$Modules += @{ Module = $Module };
}
#endregion
if ($null -ne $TemplateFileTestCases -and
$TemplateFileTestCases.Count -gt 0) {
#region Run Pester Test Script
Describe "Template: $template - Virtual Machine" -Tags Unit {
Context "Template File Syntax" {
It "Has a JSON template file" {
(Join-Path "$here" "deploy.json") | Should Exist
}
It "Converts from JSON and has the expected properties" -TestCases $TemplateFileTestCases {
Param( $TemplateFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters',
'variables',
'resources',
'outputs' | Sort-Object
$templateProperties = (Get-Content (Join-Path "$here" "$TemplateFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateProperties | Should Be $expectedProperties
}
}
Context "Parameter File Syntax" {
It "Parameter file does not contains the expected properties" -TestCases $ParameterFileTestCases {
Param( $ParameterFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters' | Sort-Object
Write-Host $ParameterFile
Join-Path "$here" "$ParameterFile" | Write-Host
$templateFileProperties = (Get-Content (Join-Path "$here" "$ParameterFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateFileProperties | Should Be $expectedProperties
}
}
Context "Template and Parameter Compactibility" {
It "Is count of required parameters in template file equal or lesser than count of all parameters in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$requiredParametersInTemplateFile.Count | Should Not BeGreaterThan $allParametersInParametersFile.Count;
}
}
It "Has all parameters in parameters file existing in template file" -TestCases $Modules {
Param( $Module )
$allParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
Write-Host "File analyzed: $Parameter";
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$result = @($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_});
Write-Host "Invalid parameters: $(ConvertTo-Json $result)";
@($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_}).Count | Should Be 0;
}
}
It "Has required parameters in template file existing in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
@($requiredParametersInTemplateFile| Where-Object {$allParametersInParametersFile -notcontains $_}).Count | Should Be 0;
}
}
}
}
#endregion
}

Просмотреть файл

@ -0,0 +1,163 @@
<#
.NOTES
==============================================================================================
Copyright(c) Microsoft Corporation. All rights reserved.
File: module.tests.ps1
Purpose: Pester - Test Virtual Machine ARM Templates
Version: 1.0.0.0 - 1st April 2019 - Azure Virtual Datacenter Development Team
==============================================================================================
.SYNOPSIS
This script contains functionality used to test Azure Virtual Machine ARM template synatax.
.DESCRIPTION
This script contains functionality used to test Azure Virtual Machine ARM template synatax.
Deployment steps of the script are outlined below.
1) Test Template File Syntax
2) Test Parameter File Syntax
3) Test Template and Parameter File Compactibility
#>
#Requires -Version 5
#region Parameters
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$here = Join-Path $here ".."
$template = Split-Path -Leaf $here
$TemplateFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "RBAC" -AdditionalChildPath @("deploy.json")) -ErrorAction SilentlyContinue -Recurse | Select-Object -ExpandProperty Name) ) {
$TemplateFileTestCases += @{ TemplateFile = $File }
}
$ParameterFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "RBAC" -AdditionalChildPath @("*parameters.json")) -ErrorAction SilentlyContinue -Recurse | Select-Object -ExpandProperty Name) ) {
$ParameterFileTestCases += @{ ParameterFile = Join-Path "RBAC" $File }
}
$Modules = @();
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "RBAC" -AdditionalChildPath @("deploy.json")) -ErrorAction SilentlyContinue ) ) {
$Module = [PSCustomObject]@{
'Template' = $null
'Parameters' = $null
}
$Module.Template = $File.FullName;
$Parameters = @();
ForEach ( $ParameterFile in (Get-ChildItem (Join-Path "$here" "RBAC" -AdditionalChildPath @("*parameters.json")) -Recurse | Select-Object -ExpandProperty Name) ) {
$Parameters += (Join-Path "$here" "RBAC" -AdditionalChildPath @("$ParameterFile") )
}
$Module.Parameters = $Parameters;
$Modules += @{ Module = $Module };
}
#endregion
if ($null -ne $TemplateFileTestCases -and
$TemplateFileTestCases.Count -gt 0) {
#region Run Pester Test Script
Describe "Template: $template - Virtual Machine" -Tags Unit {
Context "Template File Syntax" {
It "Has a JSON template file" -TestCases $TemplateFileTestCases {
(Join-Path "$here" "deploy.json") | Should Exist
}
It "Converts from JSON and has the expected properties" -TestCases $TemplateFileTestCases {
Param( $TemplateFile )
Write-Host "TF: $TemplateFile"
$expectedProperties = '$schema',
'contentVersion',
'parameters',
'variables',
'resources',
'outputs' | Sort-Object
$templateProperties = (Get-Content (Join-Path "$here" "$TemplateFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateProperties | Should Be $expectedProperties
}
}
Context "Parameter File Syntax" {
It "Parameter file does not contains the expected properties" -TestCases $ParameterFileTestCases {
Param( $ParameterFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters' | Sort-Object
Write-Host $ParameterFile
Join-Path "$here" "$ParameterFile" | Write-Host
$templateFileProperties = (Get-Content (Join-Path "$here" "$ParameterFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateFileProperties | Should Be $expectedProperties
}
}
Context "Template and Parameter Compactibility" {
It "Is count of required parameters in template file equal or lesser than count of all parameters in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$requiredParametersInTemplateFile.Count | Should Not BeGreaterThan $allParametersInParametersFile.Count;
}
}
It "Has all parameters in parameters file existing in template file" -TestCases $Modules {
Param( $Module )
$allParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
Write-Host "File analyzed: $Parameter";
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$result = @($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_});
Write-Host "Invalid parameters: $(ConvertTo-Json $result)";
@($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_}).Count | Should Be 0;
}
}
It "Has required parameters in template file existing in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
@($requiredParametersInTemplateFile| Where-Object {$allParametersInParametersFile -notcontains $_}).Count | Should Be 0;
}
}
}
}
#endregion
}

Просмотреть файл

@ -0,0 +1,42 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"proximityPlacementGroupsName": {
"type": "string",
"metadata": {
"description": "Required. The Proximity Placement Groups Name"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Optional. Location for all resources."
}
}
},
"variables": {},
"resources": [
{
"apiVersion": "2018-04-01",
"type": "Microsoft.Compute/proximityPlacementGroups",
"name": "[parameters('proximityPlacementGroupsName')]",
"location": "[parameters('location')]"
}
],
"outputs": {
"proximityPlacementGroupsName": {
"type": "string",
"value": "[parameters('proximityPlacementGroupsName')]"
},
"proximityPlacementGroupsResourceId": {
"type": "string",
"value": "[resourceId('Microsoft.Compute/proximityPlacementGroups', parameters('proximityPlacementGroupsName'))]"
},
"proximityPlacementGroupsResourceGroup": {
"type": "string",
"value": "[resourceGroup().name]"
}
}
}

Просмотреть файл

@ -1,223 +0,0 @@
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"SQLServerName": {
"type": "string",
"metadata": {
"description": "Azure SQL Server name"
}
},
"SQLserverLocation": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "The location of the SQL server."
}
},
"SQLServerAzureADAdmin": {
"type": "string",
"metadata": {
"description": "The account name to use for the SQL server administrator."
}
},
"SQLServerAzureADAdminSID": {
"type": "string"
},
"SQLServerAdminPassword": {
"type": "securestring",
"metadata": {
"description": "SQL.admin password"
}
},
"SQLServerFirewallAllowedPublicIPs": {
"type": "array",
"defaultValue": [],
"metadata": {
"description": "List of IPv4 IPs or ranges to allow access from the internet to the SQL Server"
}
},
"SQLServerFirewallAllowedSubnets": {
"type": "array",
"defaultValue": [],
"metadata": {
"description": "Information of existing virtual networks and subnets allowed to access the SQL Server"
}
},
"SQLServerMicrosoftServicesBypassFirewall": {
"type": "bool",
"defaultValue": true
},
"SecurityLogStorageAccountEndpoint": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Endpoint of the storage account where Audit Logs will be stored",
"AllEnvironmentsAutoAssignValueFromVariablesKeyVaultSecretName": "SecurityLogStorageAccountEndpoint",
"ConcatParameterAfterValue": "parameters('SQLserverLocation')"
}
},
"SecurityLogStorageAccountAccessKey": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Access Key to be used in the Audit Logs storage account",
"AllEnvironmentsAutoAssignValueFromSecretsKeyVaultSecretName": "Security-Storage-Account-PrimaryKey",
"ConcatParameterAfterValue": "parameters('SQLserverLocation')"
}
}
},
"variables": {
"SQLServerFirewallAllowedIPsArrayCount": "[length(parameters('SQLServerFirewallAllowedPublicIPs'))]",
"SQLServerFirewallAllowedIPsArrayEmpty": "[equals(variables('SQLServerFirewallAllowedIPsArrayCount'),0)]",
"SQLServerFirewallAllowedSubnetsArrayCount": "[length(parameters('SQLServerFirewallAllowedSubnets'))]",
"SQLServerFirewallAllowedSubnetsArrayEmpty": "[equals(variables('SQLServerFirewallAllowedSubnetsArrayCount'),0)]",
"EmptyArray": []
},
"resources": [
{
"name": "[parameters('SQLServerName')]",
"type": "Microsoft.Sql/servers",
"location": "[parameters('SQLserverLocation')]",
"apiVersion": "2015-05-01-preview",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"administratorLogin": "admin.SQL",
"administratorLoginPassword": "[parameters('SQLServerAdminPassword')]"
},
"resources": [
{
"condition" : "[not(equals(parameters('SecurityLogStorageAccountEndpoint'),''))]",
"apiVersion": "2017-03-01-preview",
"type": "auditingSettings",
"name": "[concat(parameters('SQLServerName'),'-auditsettings')]",
"location": "[parameters('SQLserverLocation')]",
"dependsOn": [
"[concat('Microsoft.Sql/servers/', parameters('SQLServerName'))]"
],
"properties": {
"state": "Enabled",
"storageEndpoint": "[parameters('SecurityLogStorageAccountEndpoint')]",
"storageAccountAccessKey": "[parameters('SecurityLogStorageAccountAccessKey')]",
"retentionDays": 365,
"auditActionsAndGroups": [
"BATCH_STARTED_GROUP",
"BATCH_COMPLETED_GROUP",
"APPLICATION_ROLE_CHANGE_PASSWORD_GROUP",
"BACKUP_RESTORE_GROUP",
"DATABASE_LOGOUT_GROUP",
"DATABASE_OBJECT_CHANGE_GROUP",
"DATABASE_OBJECT_OWNERSHIP_CHANGE_GROUP",
"DATABASE_OBJECT_PERMISSION_CHANGE_GROUP",
"FAILED_DATABASE_AUTHENTICATION_GROUP",
"SCHEMA_OBJECT_ACCESS_GROUP",
"SCHEMA_OBJECT_CHANGE_GROUP",
"SCHEMA_OBJECT_OWNERSHIP_CHANGE_GROUP",
"SCHEMA_OBJECT_PERMISSION_CHANGE_GROUP",
"SUCCESSFUL_DATABASE_AUTHENTICATION_GROUP",
"USER_CHANGE_PASSWORD_GROUP",
"DATABASE_PERMISSION_CHANGE_GROUP",
"DATABASE_PRINCIPAL_CHANGE_GROUP",
"DATABASE_PRINCIPAL_IMPERSONATION_GROUP",
"DATABASE_ROLE_MEMBER_CHANGE_GROUP",
"DATABASE_OPERATION_GROUP"
]
}
},
{
"condition" : "[not(equals(parameters('SecurityLogStorageAccountEndpoint'),''))]",
"apiVersion": "2015-05-01-preview",
"type": "securityAlertPolicies",
"name": "[concat(parameters('SQLServerName'),'-securityAlertsettings')]",
"dependsOn": [
"[concat('Microsoft.Sql/servers/', parameters('SQLServerName'))]",
"[concat('Microsoft.Sql/servers/', parameters('SQLServerName'),'/auditingSettings/',parameters('SQLServerName'),'-auditsettings')]"
],
"properties": {
"state": "Enabled",
"emailAccountAdmins": "Enabled",
"retentionDays": "365",
"storageEndpoint": "[parameters('SecurityLogStorageAccountEndpoint')]",
"storageAccountAccessKey": "[parameters('SecurityLogStorageAccountAccessKey')]"
}
},
{
"condition" : "[parameters('SQLServerMicrosoftServicesBypassFirewall')]",
"type": "Microsoft.Sql/servers/firewallrules",
"name": "[concat(parameters('SQLServerName'), '/', 'AllowAllWindowsAzureIps')]",
"apiVersion": "2015-05-01-preview",
"properties": {
"startIpAddress": "0.0.0.0",
"endIpAddress": "0.0.0.0"
},
"dependsOn": [
"[parameters('SQLServerName')]"
]
},
{
"type": "Microsoft.Sql/servers/administrators",
"apiVersion": "2014-04-01-preview",
"name": "[concat(parameters('SQLServerName'), '/', 'ActiveDirectory')]",
"properties": {
"administratorType": "ActiveDirectory",
"login": "[parameters('SQLServerAzureADAdmin')]",
"sid": "[parameters('SQLServerAzureADAdminSID')]",
"tenantId": "[subscription().tenantId]"
},
"dependsOn": [
"[parameters('SQLServerName')]"
]
}
]
},
{
"condition": "[not(variables('SQLServerFirewallAllowedSubnetsArrayEmpty'))]",
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Sql/servers/virtualNetworkRules",
"name": "[concat(parameters('SQLServerName'), '/', 'SubnetRule', copyIndex('SQLServerFirewallAllowedSubnets'))]",
"scale": null,
"properties": {
"virtualNetworkSubnetId": "[if(variables('SQLServerFirewallAllowedSubnetsArrayEmpty'),' ',concat('/subscriptions/',parameters('SQLServerFirewallAllowedSubnets')[copyIndex('SQLServerFirewallAllowedSubnets')].VNetSubscriptionId,'/resourceGroups/',parameters('SQLServerFirewallAllowedSubnets')[copyIndex('SQLServerFirewallAllowedSubnets')].VNetResourceGroupName,'/providers/Microsoft.Network/virtualnetworks/',parameters('SQLServerFirewallAllowedSubnets')[copyIndex('SQLServerFirewallAllowedSubnets')].VNetName,'/subnets/',parameters('SQLServerFirewallAllowedSubnets')[copyIndex('SQLServerFirewallAllowedSubnets')].VNetSubnetName))]",
"ignoreMissingVnetServiceEndpoint": false
},
"dependsOn": [
"[resourceId('Microsoft.Sql/servers', parameters('SQLServerName'))]",
"[resourceId('Microsoft.Sql/servers/administrators', parameters('SQLServerName'), 'ActiveDirectory')]",
"[concat('Microsoft.Sql/servers/', parameters('SQLServerName'),'/auditingSettings/',parameters('SQLServerName'),'-auditsettings')]",
"[concat('Microsoft.Sql/servers/', parameters('SQLServerName'),'/securityAlertPolicies/',parameters('SQLServerName'),'-securityAlertsettings')]",
"[resourceId('Microsoft.Sql/servers/firewallrules', parameters('SQLServerName'), 'AllowAllWindowsAzureIps')]"
],
"copy":
{
"name": "SQLServerFirewallAllowedSubnets",
"count": "[if(variables('SQLServerFirewallAllowedSubnetsArrayEmpty'),1,variables('SQLServerFirewallAllowedSubnetsArrayCount'))]"
}
},
{
"condition": "[not(variables('SQLServerFirewallAllowedIPsArrayEmpty'))]",
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Sql/servers/firewallRules",
"name": "[concat(parameters('SQLServerName'), '/', 'FirewallRule', copyIndex('SQLServerFirewallAllowedIPAddresses'))]",
"properties": {
"startIpAddress": "[if(variables('SQLServerFirewallAllowedIPsArrayEmpty'),' ', parameters('SQLServerFirewallAllowedPublicIPs')[copyIndex('SQLServerFirewallAllowedIPAddresses')].start)]",
"endIpAddress": "[if(variables('SQLServerFirewallAllowedIPsArrayEmpty'),' ', parameters('SQLServerFirewallAllowedPublicIPs')[copyIndex('SQLServerFirewallAllowedIPAddresses')].end)]"
},
"dependsOn": [
"[resourceId('Microsoft.Sql/servers', parameters('SQLServerName'))]",
"[resourceId('Microsoft.Sql/servers/administrators', parameters('SQLServerName'), 'ActiveDirectory')]",
"[concat('Microsoft.Sql/servers/', parameters('SQLServerName'),'/auditingSettings/',parameters('SQLServerName'),'-auditsettings')]",
"[concat('Microsoft.Sql/servers/', parameters('SQLServerName'),'/securityAlertPolicies/',parameters('SQLServerName'),'-securityAlertsettings')]",
"[resourceId('Microsoft.Sql/servers/firewallrules', parameters('SQLServerName'), 'AllowAllWindowsAzureIps')]"
],
"copy": {
"name": "SQLServerFirewallAllowedIPAddresses",
"count": "[if(variables('SQLServerFirewallAllowedIPsArrayEmpty'),1,variables('SQLServerFirewallAllowedIPsArrayCount'))]"
}
}
],
"outputs": {}
}

Просмотреть файл

@ -1,30 +0,0 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"SQLServerName": {
"value": null
},
"SQLServerAzureADAdmin": {
"value": null
},
"SQLServerAzureADAdminSID": {
"value": null
},
"SQLServerAdminPassword": {
"value": null
},
"SQLServerFirewallAllowedPublicIPs": {
"value": []
},
"SQLServerFirewallAllowedSubnets": {
"value": []
},
"SecurityLogStorageAccountEndpoint": {
"value": null
},
"SecurityLogStorageAccountAccessKey": {
"value": null
}
}
}

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -5,7 +5,7 @@
File: module.tests.ps1
Purpose: Pester - Test Storage Account ARM Templates
Purpose: Pester - Test Virtual Machine ARM Templates
Version: 1.0.0.0 - 1st April 2019 - Azure Virtual Datacenter Development Team
==============================================================================================
@ -34,25 +34,28 @@ ForEach ( $File in (Get-ChildItem (Join-Path "$here" "deploy.json") -Recurse | S
$TemplateFileTestCases += @{ TemplateFile = $File }
}
$ParameterFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "parameters.json") -Recurse | Select-Object -ExpandProperty Name) ) {
$ParameterFileTestCases += @{ ParameterFile = $File }
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "Tests" -AdditionalChildPath @("*parameters.json")) -Recurse -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Name) ) {
$ParameterFileTestCases += @{ ParameterFile = Join-Path "Tests" $File }
}
$Modules = @();
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "deploy.json") -Recurse ) ) {
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "deploy.json") ) ) {
$Module = [PSCustomObject]@{
'Template' = $null
'Parameters' = $null
}
$Module.Template = $File.FullName;
$Module.Parameters = (Get-ChildItem -Path (Join-Path $($File.DirectoryName) "parameters.json")).FullName;
$Parameters = @();
ForEach ( $ParameterFile in (Get-ChildItem (Join-Path "$here" "Tests" -AdditionalChildPath @("*parameters.json")) -Recurse -ErrorAction SilentlyContinue| Select-Object -ExpandProperty Name) ) {
$Parameters += (Join-Path "$here" "Tests" -AdditionalChildPath @("$ParameterFile") )
}
$Module.Parameters = $Parameters;
$Modules += @{ Module = $Module };
}
#endregion
#region Run Pester Test Script
Describe "Template: $template - Storage Accounts" -Tags Unit {
Describe "Template: $template - Virtual Machine" -Tags Unit {
Context "Template File Syntax" {
@ -79,15 +82,13 @@ Describe "Template: $template - Storage Accounts" -Tags Unit {
Context "Parameter File Syntax" {
It "Has environment parameters file" {
(Join-Path "$here" "parameters.json") | Should Exist
}
It "Parameter file does not contains the expected properties" -TestCases $ParameterFileTestCases {
Param( $ParameterFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters' | Sort-Object
'parameters' | Sort-Object
Write-Host $ParameterFile
Join-Path "$here" "$ParameterFile" | Write-Host
$templateFileProperties = (Get-Content (Join-Path "$here" "$ParameterFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
@ -98,7 +99,6 @@ Describe "Template: $template - Storage Accounts" -Tags Unit {
}
Context "Template and Parameter Compactibility" {
It "Is count of required parameters in template file equal or lesser than count of all parameters in parameters file" -TestCases $Modules {
@ -109,12 +109,13 @@ Describe "Template: $template - Storage Accounts" -Tags Unit {
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
$allParametersInParametersFile = (Get-Content "$($Module.Parameters)" `
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$requiredParametersInTemplateFile.Count | Should Not BeGreaterThan $allParametersInParametersFile.Count;
$requiredParametersInTemplateFile.Count | Should Not BeGreaterThan $allParametersInParametersFile.Count;
}
}
It "Has all parameters in parameters file existing in template file" -TestCases $Modules {
@ -124,11 +125,20 @@ Describe "Template: $template - Storage Accounts" -Tags Unit {
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$allParametersInParametersFile = (Get-Content "$($Module.Parameters)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
@($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_}).Count | Should Be 0;
ForEach ( $Parameter in $Module.Parameters ) {
Write-Host "File analyzed: $Parameter";
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$result = @($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_});
if ($result.Count -gt 0) {
Write-Host "Invalid parameters: $(ConvertTo-Json $result)"
}
@($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_}).Count | Should Be 0;
}
}
It "Has required parameters in template file existing in parameters file" -TestCases $Modules {
@ -139,11 +149,22 @@ Describe "Template: $template - Storage Accounts" -Tags Unit {
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
$allParametersInParametersFile = (Get-Content "$($Module.Parameters)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
@($requiredParametersInTemplateFile| Where-Object {$allParametersInParametersFile -notcontains $_}).Count | Should Be 0;
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$invalidParameters = `
$requiredParametersInTemplateFile | Where-Object {$allParametersInParametersFile -notcontains $_}
if ($invalidParameters.Count -gt 0) {
Write-Host "Parameters not found: $(ConvertTo-Json $invalidParameters)"
}
$invalidParameters.Count | Should Be 0
}
}
}

Просмотреть файл

@ -0,0 +1,45 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"virtualMachineName": {
"value": "string"
},
"adminUsername": {
"value": "securestring"
},
"adminPassword": {
"value": "securestring"
},
"clusterName": {
"value": "securestring"
},
"artifactsStorageAccountName": {
"value": "securestring"
},
"artifactsStorageAccountKey": {
"value": "securestring"
},
"artifactsStorageAccountSasKey": {
"value": "securestring"
},
"cloudWitnessStorageAccountName": {
"value": "securestring"
},
"cloudWitnessStorageAccountKey": {
"value": "securestring"
},
"sqlServerILB_IPAddress": {
"value": "securestring"
},
"domainName": {
"value": "securestring"
},
"domainAdminUsername": {
"value": "securestring"
},
"domainAdminPassword": {
"value": "securestring"
}
}
}

Просмотреть файл

@ -0,0 +1,163 @@
<#
.NOTES
==============================================================================================
Copyright(c) Microsoft Corporation. All rights reserved.
File: module.tests.ps1
Purpose: Pester - Test Virtual Machine ARM Templates
Version: 1.0.0.0 - 1st April 2019 - Azure Virtual Datacenter Development Team
==============================================================================================
.SYNOPSIS
This script contains functionality used to test Azure Virtual Machine ARM template synatax.
.DESCRIPTION
This script contains functionality used to test Azure Virtual Machine ARM template synatax.
Deployment steps of the script are outlined below.
1) Test Template File Syntax
2) Test Parameter File Syntax
3) Test Template and Parameter File Compactibility
#>
#Requires -Version 5
#region Parameters
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$here = Join-Path $here ".."
$template = Split-Path -Leaf $here
$TemplateFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "Policy" -AdditionalChildPath @("deploy.json")) -Recurse -ErrorAction SilentlyContinue| Select-Object -ExpandProperty Name) ) {
$TemplateFileTestCases += @{ TemplateFile = $File }
}
$ParameterFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "Policy" -AdditionalChildPath @("*parameters.json")) -Recurse -ErrorAction SilentlyContinue| Select-Object -ExpandProperty Name) ) {
$ParameterFileTestCases += @{ ParameterFile = Join-Path "Policy" $File }
}
$Modules = @();
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "Policy" -AdditionalChildPath @("deploy.json")) -ErrorAction SilentlyContinue ) ) {
$Module = [PSCustomObject]@{
'Template' = $null
'Parameters' = $null
}
$Module.Template = $File.FullName;
$Parameters = @();
ForEach ( $ParameterFile in (Get-ChildItem (Join-Path "$here" "Policy" -AdditionalChildPath @("*parameters.json")) -Recurse -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Name) ) {
$Parameters += (Join-Path "$here" "Policy" -AdditionalChildPath @("$ParameterFile") )
}
$Module.Parameters = $Parameters;
$Modules += @{ Module = $Module };
}
#endregion
if ($null -ne $TemplateFileTestCases -and
$TemplateFileTestCases.Count -gt 0) {
#region Run Pester Test Script
Describe "Template: $template - Virtual Machine" -Tags Unit {
Context "Template File Syntax" {
It "Has a JSON template file" {
(Join-Path "$here" "deploy.json") | Should Exist
}
It "Converts from JSON and has the expected properties" -TestCases $TemplateFileTestCases {
Param( $TemplateFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters',
'variables',
'resources',
'outputs' | Sort-Object
$templateProperties = (Get-Content (Join-Path "$here" "$TemplateFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateProperties | Should Be $expectedProperties
}
}
Context "Parameter File Syntax" {
It "Parameter file does not contains the expected properties" -TestCases $ParameterFileTestCases {
Param( $ParameterFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters' | Sort-Object
Write-Host $ParameterFile
Join-Path "$here" "$ParameterFile" | Write-Host
$templateFileProperties = (Get-Content (Join-Path "$here" "$ParameterFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateFileProperties | Should Be $expectedProperties
}
}
Context "Template and Parameter Compactibility" {
It "Is count of required parameters in template file equal or lesser than count of all parameters in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$requiredParametersInTemplateFile.Count | Should Not BeGreaterThan $allParametersInParametersFile.Count;
}
}
It "Has all parameters in parameters file existing in template file" -TestCases $Modules {
Param( $Module )
$allParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
Write-Host "File analyzed: $Parameter";
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$result = @($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_});
Write-Host "Invalid parameters: $(ConvertTo-Json $result)";
@($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_}).Count | Should Be 0;
}
}
It "Has required parameters in template file existing in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
@($requiredParametersInTemplateFile| Where-Object {$allParametersInParametersFile -notcontains $_}).Count | Should Be 0;
}
}
}
}
#endregion
}

Просмотреть файл

@ -0,0 +1,163 @@
<#
.NOTES
==============================================================================================
Copyright(c) Microsoft Corporation. All rights reserved.
File: module.tests.ps1
Purpose: Pester - Test Virtual Machine ARM Templates
Version: 1.0.0.0 - 1st April 2019 - Azure Virtual Datacenter Development Team
==============================================================================================
.SYNOPSIS
This script contains functionality used to test Azure Virtual Machine ARM template synatax.
.DESCRIPTION
This script contains functionality used to test Azure Virtual Machine ARM template synatax.
Deployment steps of the script are outlined below.
1) Test Template File Syntax
2) Test Parameter File Syntax
3) Test Template and Parameter File Compactibility
#>
#Requires -Version 5
#region Parameters
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$here = Join-Path $here ".."
$template = Split-Path -Leaf $here
$TemplateFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "RBAC" -AdditionalChildPath @("deploy.json")) -ErrorAction SilentlyContinue -Recurse | Select-Object -ExpandProperty Name) ) {
$TemplateFileTestCases += @{ TemplateFile = $File }
}
$ParameterFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "RBAC" -AdditionalChildPath @("*parameters.json")) -ErrorAction SilentlyContinue -Recurse | Select-Object -ExpandProperty Name) ) {
$ParameterFileTestCases += @{ ParameterFile = Join-Path "RBAC" $File }
}
$Modules = @();
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "RBAC" -AdditionalChildPath @("deploy.json")) -ErrorAction SilentlyContinue ) ) {
$Module = [PSCustomObject]@{
'Template' = $null
'Parameters' = $null
}
$Module.Template = $File.FullName;
$Parameters = @();
ForEach ( $ParameterFile in (Get-ChildItem (Join-Path "$here" "RBAC" -AdditionalChildPath @("*parameters.json")) -Recurse | Select-Object -ExpandProperty Name) ) {
$Parameters += (Join-Path "$here" "RBAC" -AdditionalChildPath @("$ParameterFile") )
}
$Module.Parameters = $Parameters;
$Modules += @{ Module = $Module };
}
#endregion
if ($null -ne $TemplateFileTestCases -and
$TemplateFileTestCases.Count -gt 0) {
#region Run Pester Test Script
Describe "Template: $template - Virtual Machine" -Tags Unit {
Context "Template File Syntax" {
It "Has a JSON template file" -TestCases $TemplateFileTestCases {
(Join-Path "$here" "deploy.json") | Should Exist
}
It "Converts from JSON and has the expected properties" -TestCases $TemplateFileTestCases {
Param( $TemplateFile )
Write-Host "TF: $TemplateFile"
$expectedProperties = '$schema',
'contentVersion',
'parameters',
'variables',
'resources',
'outputs' | Sort-Object
$templateProperties = (Get-Content (Join-Path "$here" "$TemplateFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateProperties | Should Be $expectedProperties
}
}
Context "Parameter File Syntax" {
It "Parameter file does not contains the expected properties" -TestCases $ParameterFileTestCases {
Param( $ParameterFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters' | Sort-Object
Write-Host $ParameterFile
Join-Path "$here" "$ParameterFile" | Write-Host
$templateFileProperties = (Get-Content (Join-Path "$here" "$ParameterFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateFileProperties | Should Be $expectedProperties
}
}
Context "Template and Parameter Compactibility" {
It "Is count of required parameters in template file equal or lesser than count of all parameters in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$requiredParametersInTemplateFile.Count | Should Not BeGreaterThan $allParametersInParametersFile.Count;
}
}
It "Has all parameters in parameters file existing in template file" -TestCases $Modules {
Param( $Module )
$allParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
Write-Host "File analyzed: $Parameter";
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$result = @($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_});
Write-Host "Invalid parameters: $(ConvertTo-Json $result)";
@($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_}).Count | Should Be 0;
}
}
It "Has required parameters in template file existing in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
@($requiredParametersInTemplateFile| Where-Object {$allParametersInParametersFile -notcontains $_}).Count | Should Be 0;
}
}
}
}
#endregion
}

Просмотреть файл

@ -0,0 +1,414 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"virtualMachineName": {
"type": "string",
"minLength": 1,
"maxLength": 13,
"metadata": {
"description": "Required. Name for the VMs"
}
},
"virtualMachineCount": {
"type": "int",
"defaultValue": 1,
"metadata": {
"description": "Optional. Number of VMs to create"
}
},
"virtualMachineOffset": {
"type": "int",
"defaultValue": 1,
"metadata": {
"description": "Optional. This value will be used as start VM count. Specify a value if you want to create VMs starting at a specific number, this is useful when you want to append more VMs."
}
},
"adminUsername": {
"type": "securestring",
"metadata": {
"description": "Required. Administrator username"
}
},
"adminPassword": {
"type": "securestring",
"metadata": {
"description": "Required. When specifying a Windows Virtual Machine, this value should be passed"
}
},
"clusterName": {
"type": "string",
"metadata": {
"description": "Required. SQL Server AlwaysOn Cluster name"
}
},
"artifactsStorageAccountName": {
"type": "securestring",
"metadata": {
"description": "Required. Default storage account name. Storage account that contains output parameters and common scripts"
}
},
"artifactsStorageAccountKey": {
"type": "securestring",
"metadata": {
"description": "Required. Default storage account Key. Storage account that contains output parameters and common scripts"
}
},
"artifactsStorageAccountSasKey": {
"type": "securestring",
"metadata": {
"description": "Required. Shared Access Signature Key used to download custom scripts"
}
},
"cloudWitnessStorageAccountName": {
"type": "securestring",
"metadata": {
"description": "Required. Default storage account name. Storage account that contains output parameters and common scripts"
}
},
"cloudWitnessStorageAccountKey": {
"type": "securestring",
"metadata": {
"description": "Required. Default storage account Key. Storage account that contains output parameters and common scripts"
}
},
"sqlServerILB_IPAddress": {
"type": "string",
"metadata": {
"description": "Required. SQL Server Internal Load Balancer IP Address"
}
},
"domainName": {
"type": "securestring",
"metadata": {
"description": "Required. AD domain name. If joinToDomain is set to true, this value becomes required."
}
},
"domainAdminUsername": {
"type": "securestring",
"metadata": {
"description": "Required. Domain user that has privileges to join a VM into a Domain. If joinToDomain is set to true, this value becomes required."
}
},
"domainAdminPassword": {
"type": "securestring",
"metadata": {
"description": "Required. Domain user that has privileges to join a VM into a Domain. If joinToDomain is set to true, this value becomes required."
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Optional. Location for all resources."
}
}
},
"variables": {
"DSCExtensionName": "DSCExtension",
"PwshExtensionName": "PwshExtension",
"artifactsStorageAccountSasToken": "[concat('?', parameters('artifactsStorageAccountSasKey'))]"
},
"resources": [
{
"apiVersion": "2017-03-30",
"type": "Microsoft.Compute/virtualMachines",
"name": "[concat(parameters('virtualMachineName'), copyIndex(parameters('virtualMachineOffset')))]",
"location": "[parameters('location')]",
"copy": {
"name": "vmInstallDSCModulesLoop",
"count": "[parameters('virtualMachineCount')]"
},
"resources": [
{
"type": "extensions",
"name": "[variables('PwshExtensionName')]",
"apiVersion": "2017-03-30",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Compute/virtualMachines', concat(parameters('virtualMachineName'), copyIndex(parameters('virtualMachineOffset'))))]"
],
"properties": {
"publisher": "Microsoft.Compute",
"type": "CustomScriptExtension",
"typeHandlerVersion": "1.8",
"autoUpgradeMinorVersion": true,
"settings": {
"fileUris": [
"[concat('https://', parameters('artifactsStorageAccountName'), '.blob.core.windows.net/scripts/Windows/PrepareSQLServer_Install_Modules.ps1')]"
]
},
"protectedSettings": {
"storageAccountName": "[parameters('artifactsStorageAccountName')]",
"storageAccountKey": "[parameters('artifactsStorageAccountKey')]",
"commandToExecute": "powershell -ExecutionPolicy Unrestricted -File ./windows/PrepareSQLServer_Install_Modules.ps1"
}
}
}
]
},
{
"name": "vm1NestedDeploymentSetupSQL",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2016-09-01",
"dependsOn": [
"vmInstallDSCModulesLoop"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"resources": [
{
"apiVersion": "2017-03-30",
"type": "Microsoft.Compute/virtualMachines",
"name": "[concat(parameters('virtualMachineName'), '1')]",
"location": "[parameters('location')]",
"resources": [
{
"type": "extensions",
"name": "[variables('DSCExtensionName')]",
"apiVersion": "2017-03-30",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Compute/virtualMachines', concat(parameters('virtualMachineName'), '1'))]"
],
"properties": {
"publisher": "Microsoft.Powershell",
"type": "DSC",
"typeHandlerVersion": "2.7",
"autoUpgradeMinorVersion": true,
"settings": {
"configuration": {
"url": "[concat('https://', parameters('artifactsStorageAccountName'), '.blob.core.windows.net/scripts/windows/PrepareSQLServer.ps1.zip')]",
"script": "PrepareSqlServer.ps1",
"function": "SqlServerPrepareDsc"
},
"configurationArguments": {
"DomainName": "[parameters('domainName')]",
"ClusterName": "[parameters('clusterName')]",
"ClusterOwnerNode": "[concat(parameters('virtualMachineName'), '1')]",
"ClusterIP": "[parameters('sqlServerILB_IPAddress')]",
"witnessStorageBlobEndPoint": "[concat('https://', parameters('cloudWitnessStorageAccountName'), '.blob.core.windows.net')]",
"witnessStorageAccountKey": "[parameters('cloudWitnessStorageAccountKey')]"
}
},
"protectedSettings": {
"configurationUrlSasToken": "[variables('artifactsStorageAccountSasToken')]",
"configurationArguments": {
"AdminCreds": {
"UserName": "[parameters('domainAdminUsername')]",
"Password": "[parameters('domainAdminPassword')]"
},
"sqlServiceCreds": {
"UserName": "[parameters('adminUsername')]",
"Password": "[parameters('adminPassword')]"
}
}
}
}
}
]
}
]
},
"parameters": {}
}
},
{
"name": "NestedDeploymentSleep",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2016-09-01",
"dependsOn": [
"vm1NestedDeploymentSetupSQL"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"resources": [
{
"apiVersion": "2017-03-30",
"type": "Microsoft.Compute/virtualMachines",
"name": "[concat(parameters('virtualMachineName'), '1')]",
"location": "[parameters('location')]",
"resources": [
{
"type": "extensions",
"name": "[variables('PwshExtensionName')]",
"apiVersion": "2017-03-30",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Compute/virtualMachines', concat(parameters('virtualMachineName'), '1'))]"
],
"properties": {
"publisher": "Microsoft.Compute",
"type": "CustomScriptExtension",
"typeHandlerVersion": "1.8",
"autoUpgradeMinorVersion": true,
"settings": {
"fileUris": [
"[concat('https://', parameters('artifactsStorageAccountName'), '.blob.core.windows.net/scripts/Windows/sleep.ps1')]"
]
},
"protectedSettings": {
"storageAccountName": "[parameters('artifactsStorageAccountName')]",
"storageAccountKey": "[parameters('artifactsStorageAccountKey')]",
"commandToExecute": "powershell -ExecutionPolicy Unrestricted -File ./windows/sleep.ps1 -Sleep 600"
}
}
}
]
}
]
},
"parameters": {}
}
},
{
"name": "vm2NestedDeploymentSetupSQL",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2016-09-01",
"dependsOn": [
"NestedDeploymentSleep"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"resources": [
{
"apiVersion": "2017-03-30",
"type": "Microsoft.Compute/virtualMachines",
"name": "[concat(parameters('virtualMachineName'), '2')]",
"location": "[parameters('location')]",
"resources": [
{
"type": "extensions",
"name": "[variables('DSCExtensionName')]",
"apiVersion": "2017-03-30",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Compute/virtualMachines', concat(parameters('virtualMachineName'), '2'))]"
],
"properties": {
"publisher": "Microsoft.Powershell",
"type": "DSC",
"typeHandlerVersion": "2.7",
"autoUpgradeMinorVersion": true,
"settings": {
"configuration": {
"url": "[concat('https://', parameters('artifactsStorageAccountName'), '.blob.core.windows.net/scripts/Windows/PrepareSQLServer.ps1.zip')]",
"script": "PrepareSqlServer.ps1",
"function": "SqlServerPrepareDsc"
},
"configurationArguments": {
"DomainName": "[parameters('domainName')]",
"ClusterName": "[parameters('clusterName')]",
"ClusterOwnerNode": "[concat(parameters('virtualMachineName'), '1')]",
"ClusterIP": "[parameters('sqlServerILB_IPAddress')]",
"witnessStorageBlobEndPoint": "[concat('https://', parameters('cloudWitnessStorageAccountName'), '.blob.core.windows.net')]",
"witnessStorageAccountKey": "[parameters('cloudWitnessStorageAccountKey')]"
}
},
"protectedSettings": {
"configurationUrlSasToken": "[variables('artifactsStorageAccountSasToken')]",
"configurationArguments": {
"AdminCreds": {
"UserName": "[parameters('domainAdminUsername')]",
"Password": "[parameters('domainAdminPassword')]"
},
"sqlServiceCreds": {
"UserName": "[parameters('adminUsername')]",
"Password": "[parameters('adminPassword')]"
}
}
}
}
}
]
}
]
},
"parameters": {}
}
},
{
"name": "vm1NestedDeploymentSetupSQLAG",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2016-09-01",
"dependsOn": [
"vm2NestedDeploymentSetupSQL"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"resources": [
{
"apiVersion": "2017-03-30",
"type": "Microsoft.Compute/virtualMachines",
"name": "[concat(parameters('virtualMachineName'), '1')]",
"location": "[parameters('location')]",
"resources": [
{
"type": "extensions",
"name": "[variables('DSCExtensionName')]",
"apiVersion": "2017-03-30",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Compute/virtualMachines', concat(parameters('virtualMachineName'), '1'))]"
],
"properties": {
"publisher": "Microsoft.Powershell",
"type": "DSC",
"typeHandlerVersion": "2.7",
"autoUpgradeMinorVersion": true,
"settings": {
"configuration": {
"url": "[concat('https://', parameters('artifactsStorageAccountName'), '.blob.core.windows.net/scripts/Windows/CreateHADB.ps1.zip')]",
"script": "agdb.ps1",
"function": "SQLServerDBDsc"
},
"configurationArguments": {
"DomainName": "[parameters('domainName')]",
"ClusterName": "[parameters('clusterName')]",
"ClusterOwnerNode": "[concat(parameters('virtualMachineName'), '1')]",
"ClusterIP": "[parameters('sqlServerILB_IPAddress')]",
"witnessStorageBlobEndPoint": "[concat('https://', parameters('cloudWitnessStorageAccountName'), '.blob.core.windows.net')]",
"witnessStorageAccountKey": "[parameters('cloudWitnessStorageAccountKey')]"
}
},
"protectedSettings": {
"configurationUrlSasToken": "[variables('artifactsStorageAccountSasToken')]",
"configurationArguments": {
"AdminCreds": {
"UserName": "[parameters('domainAdminUsername')]",
"Password": "[parameters('domainAdminPassword')]"
},
"sqlServiceCreds": {
"UserName": "[parameters('adminUsername')]",
"Password": "[parameters('adminPassword')]"
}
}
}
}
}
]
}
]
},
"parameters": {}
}
}
],
"outputs": {}
}

Просмотреть файл

@ -1,6 +1,6 @@
# SQL Server
This template deploys an SQL Server.
This template deploys an SQL Server Always On Virtual Machines using Cloud Witness.
## Deployed Resources

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -0,0 +1,56 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"virtualMachineScaleSetsName": {
"value": "adds"
},
"virtualMachineScaleSetsSku": {
"value": {
"name": "SKUName",
"tier": "Standard",
"capacity": 5
}
},
"virtualMachineScaleSetsOSImage": {
"value": {
"publisher": "Canonical",
"offer": "UbuntuServer",
"sku": "18.04-LTS"
}
},
"virtualMachineScaleSetsOSType": {
"value": "Linux"
},
"workspaceId": {
"value": "00000000-0000-0000-0000-000000000000"
},
"logAnalyticsWorkspacePrimarySharedKey": {
"value": ""
},
"diagnosticsStorageAccountName": {
"value": "contoso-diag-storage"
},
"diagnosticsStorageAccountSasToken": {
"value": ""
},
"artifactsStorageAccountName": {
"value": "contoso-diag-storage"
},
"artifactsStorageAccountSasKey": {
"value": ""
},
"vNetId": {
"value": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourceGroup/providers/Microsoft.Network/virtualNetworks/contoso-vnet-example"
},
"subnetName": {
"value": "sharedsvcs"
},
"adminUsername": {
"value": "contoso"
},
"sshPublicKey": {
"value": "password"
}
}
}

Просмотреть файл

@ -0,0 +1,164 @@
<#
.NOTES
==============================================================================================
Copyright(c) Microsoft Corporation. All rights reserved.
File: module.tests.ps1
Purpose: Pester - Test Virtual Machine Scale Sets Scale Set ARM Templates
Version: 1.0.0.0 - 1st April 2019 - Azure Virtual Datacenter Development Team
==============================================================================================
.SYNOPSIS
This script contains functionality used to test Virtual Machine Scale Sets Scale Set ARM template synatax.
.DESCRIPTION
This script contains functionality used to test Virtual Machine Scale Sets Scale Set ARM template synatax.
Deployment steps of the script are outlined below.
1) Test Template File Syntax
2) Test Parameter File Syntax
3) Test Template and Parameter File Compactibility
#>
#Requires -Version 5
#region Parameters
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$here = Join-Path $here ".."
$template = Split-Path -Leaf $here
$TemplateFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "deploy.json") -Recurse | Select-Object -ExpandProperty Name) ) {
$TemplateFileTestCases += @{ TemplateFile = $File }
}
$ParameterFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "Tests" -AdditionalChildPath @("*parameters.json")) -Recurse -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Name) ) {
$ParameterFileTestCases += @{ ParameterFile = Join-Path "Tests" $File }
}
$Modules = @();
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "deploy.json") ) ) {
$Module = [PSCustomObject]@{
'Template' = $null
'Parameters' = $null
}
$Module.Template = $File.FullName;
$Parameters = @();
ForEach ( $ParameterFile in (Get-ChildItem (Join-Path "$here" "Tests" -AdditionalChildPath @("*parameters.json")) -Recurse -ErrorAction SilentlyContinue| Select-Object -ExpandProperty Name) ) {
$Parameters += (Join-Path "$here" "Tests" -AdditionalChildPath @("$ParameterFile") )
}
$Module.Parameters = $Parameters;
$Modules += @{ Module = $Module };
}
#endregion
#region Run Pester Test Script
Describe "Template: $template - Virtual Machine Scale Sets" -Tags Unit {
Context "Template File Syntax" {
It "Has a JSON template file" {
(Join-Path "$here" "deploy.json") | Should Exist
}
It "Converts from JSON and has the expected properties" -TestCases $TemplateFileTestCases {
Param( $TemplateFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters',
'variables',
'resources',
'outputs' | Sort-Object
$templateProperties = (Get-Content (Join-Path "$here" "$TemplateFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateProperties | Should Be $expectedProperties
}
}
Context "Parameter File Syntax" {
It "Parameter file does not contains the expected properties" -TestCases $ParameterFileTestCases {
Param( $ParameterFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters' | Sort-Object
Write-Host $ParameterFile
Join-Path "$here" "$ParameterFile" | Write-Host
$templateFileProperties = (Get-Content (Join-Path "$here" "$ParameterFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateFileProperties | Should Be $expectedProperties
}
}
Context "Template and Parameter Compactibility" {
It "Is count of required parameters in template file equal or lesser than count of all parameters in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
Write-Host "Required: $(ConvertTo-Json $requiredParametersInTemplateFile)"
ForEach ( $Parameter in $Module.Parameters ) {
Write-Host "File: $Parameter"
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
Write-Host "Got: $(ConvertTo-Json $allParametersInParametersFile)"
$requiredParametersInTemplateFile.Count | Should Not BeGreaterThan $allParametersInParametersFile.Count;
}
}
It "Has all parameters in parameters file existing in template file" -TestCases $Modules {
Param( $Module )
$allParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
Write-Host "File analyzed: $Parameter";
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$result = @($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_});
Write-Host "Invalid parameters: $(ConvertTo-Json $result)";
@($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_}).Count | Should Be 0;
}
}
It "Has required parameters in template file existing in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
@($requiredParametersInTemplateFile | Where-Object {$allParametersInParametersFile -notcontains $_}).Count | Should Be 0;
}
}
}
}
#endregion

Просмотреть файл

@ -0,0 +1,163 @@
<#
.NOTES
==============================================================================================
Copyright(c) Microsoft Corporation. All rights reserved.
File: module.tests.ps1
Purpose: Pester - Test Virtual Machine ARM Templates
Version: 1.0.0.0 - 1st April 2019 - Azure Virtual Datacenter Development Team
==============================================================================================
.SYNOPSIS
This script contains functionality used to test Azure Virtual Machine ARM template synatax.
.DESCRIPTION
This script contains functionality used to test Azure Virtual Machine ARM template synatax.
Deployment steps of the script are outlined below.
1) Test Template File Syntax
2) Test Parameter File Syntax
3) Test Template and Parameter File Compactibility
#>
#Requires -Version 5
#region Parameters
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$here = Join-Path $here ".."
$template = Split-Path -Leaf $here
$TemplateFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "Policy" -AdditionalChildPath @("deploy.json")) -Recurse -ErrorAction SilentlyContinue| Select-Object -ExpandProperty Name) ) {
$TemplateFileTestCases += @{ TemplateFile = $File }
}
$ParameterFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "Policy" -AdditionalChildPath @("*parameters.json")) -Recurse -ErrorAction SilentlyContinue| Select-Object -ExpandProperty Name) ) {
$ParameterFileTestCases += @{ ParameterFile = Join-Path "Policy" $File }
}
$Modules = @();
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "Policy" -AdditionalChildPath @("deploy.json")) -ErrorAction SilentlyContinue ) ) {
$Module = [PSCustomObject]@{
'Template' = $null
'Parameters' = $null
}
$Module.Template = $File.FullName;
$Parameters = @();
ForEach ( $ParameterFile in (Get-ChildItem (Join-Path "$here" "Policy" -AdditionalChildPath @("*parameters.json")) -Recurse -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Name) ) {
$Parameters += (Join-Path "$here" "Policy" -AdditionalChildPath @("$ParameterFile") )
}
$Module.Parameters = $Parameters;
$Modules += @{ Module = $Module };
}
#endregion
if ($null -ne $TemplateFileTestCases -and
$TemplateFileTestCases.Count -gt 0) {
#region Run Pester Test Script
Describe "Template: $template - Virtual Machine" -Tags Unit {
Context "Template File Syntax" {
It "Has a JSON template file" {
(Join-Path "$here" "deploy.json") | Should Exist
}
It "Converts from JSON and has the expected properties" -TestCases $TemplateFileTestCases {
Param( $TemplateFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters',
'variables',
'resources',
'outputs' | Sort-Object
$templateProperties = (Get-Content (Join-Path "$here" "$TemplateFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateProperties | Should Be $expectedProperties
}
}
Context "Parameter File Syntax" {
It "Parameter file does not contains the expected properties" -TestCases $ParameterFileTestCases {
Param( $ParameterFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters' | Sort-Object
Write-Host $ParameterFile
Join-Path "$here" "$ParameterFile" | Write-Host
$templateFileProperties = (Get-Content (Join-Path "$here" "$ParameterFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateFileProperties | Should Be $expectedProperties
}
}
Context "Template and Parameter Compactibility" {
It "Is count of required parameters in template file equal or lesser than count of all parameters in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$requiredParametersInTemplateFile.Count | Should Not BeGreaterThan $allParametersInParametersFile.Count;
}
}
It "Has all parameters in parameters file existing in template file" -TestCases $Modules {
Param( $Module )
$allParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
Write-Host "File analyzed: $Parameter";
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$result = @($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_});
Write-Host "Invalid parameters: $(ConvertTo-Json $result)";
@($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_}).Count | Should Be 0;
}
}
It "Has required parameters in template file existing in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
@($requiredParametersInTemplateFile| Where-Object {$allParametersInParametersFile -notcontains $_}).Count | Should Be 0;
}
}
}
}
#endregion
}

Просмотреть файл

@ -0,0 +1,163 @@
<#
.NOTES
==============================================================================================
Copyright(c) Microsoft Corporation. All rights reserved.
File: module.tests.ps1
Purpose: Pester - Test Virtual Machine ARM Templates
Version: 1.0.0.0 - 1st April 2019 - Azure Virtual Datacenter Development Team
==============================================================================================
.SYNOPSIS
This script contains functionality used to test Azure Virtual Machine ARM template synatax.
.DESCRIPTION
This script contains functionality used to test Azure Virtual Machine ARM template synatax.
Deployment steps of the script are outlined below.
1) Test Template File Syntax
2) Test Parameter File Syntax
3) Test Template and Parameter File Compactibility
#>
#Requires -Version 5
#region Parameters
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$here = Join-Path $here ".."
$template = Split-Path -Leaf $here
$TemplateFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "RBAC" -AdditionalChildPath @("deploy.json")) -ErrorAction SilentlyContinue -Recurse | Select-Object -ExpandProperty Name) ) {
$TemplateFileTestCases += @{ TemplateFile = $File }
}
$ParameterFileTestCases = @()
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "RBAC" -AdditionalChildPath @("*parameters.json")) -ErrorAction SilentlyContinue -Recurse | Select-Object -ExpandProperty Name) ) {
$ParameterFileTestCases += @{ ParameterFile = Join-Path "RBAC" $File }
}
$Modules = @();
ForEach ( $File in (Get-ChildItem (Join-Path "$here" "RBAC" -AdditionalChildPath @("deploy.json")) -ErrorAction SilentlyContinue ) ) {
$Module = [PSCustomObject]@{
'Template' = $null
'Parameters' = $null
}
$Module.Template = $File.FullName;
$Parameters = @();
ForEach ( $ParameterFile in (Get-ChildItem (Join-Path "$here" "RBAC" -AdditionalChildPath @("*parameters.json")) -Recurse | Select-Object -ExpandProperty Name) ) {
$Parameters += (Join-Path "$here" "RBAC" -AdditionalChildPath @("$ParameterFile") )
}
$Module.Parameters = $Parameters;
$Modules += @{ Module = $Module };
}
#endregion
if ($null -ne $TemplateFileTestCases -and
$TemplateFileTestCases.Count -gt 0) {
#region Run Pester Test Script
Describe "Template: $template - Virtual Machine" -Tags Unit {
Context "Template File Syntax" {
It "Has a JSON template file" -TestCases $TemplateFileTestCases {
(Join-Path "$here" "deploy.json") | Should Exist
}
It "Converts from JSON and has the expected properties" -TestCases $TemplateFileTestCases {
Param( $TemplateFile )
Write-Host "TF: $TemplateFile"
$expectedProperties = '$schema',
'contentVersion',
'parameters',
'variables',
'resources',
'outputs' | Sort-Object
$templateProperties = (Get-Content (Join-Path "$here" "$TemplateFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateProperties | Should Be $expectedProperties
}
}
Context "Parameter File Syntax" {
It "Parameter file does not contains the expected properties" -TestCases $ParameterFileTestCases {
Param( $ParameterFile )
$expectedProperties = '$schema',
'contentVersion',
'parameters' | Sort-Object
Write-Host $ParameterFile
Join-Path "$here" "$ParameterFile" | Write-Host
$templateFileProperties = (Get-Content (Join-Path "$here" "$ParameterFile") `
| ConvertFrom-Json -ErrorAction SilentlyContinue) `
| Get-Member -MemberType NoteProperty `
| Sort-Object -Property Name `
| ForEach-Object Name
$templateFileProperties | Should Be $expectedProperties
}
}
Context "Template and Parameter Compactibility" {
It "Is count of required parameters in template file equal or lesser than count of all parameters in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$requiredParametersInTemplateFile.Count | Should Not BeGreaterThan $allParametersInParametersFile.Count;
}
}
It "Has all parameters in parameters file existing in template file" -TestCases $Modules {
Param( $Module )
$allParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
Write-Host "File analyzed: $Parameter";
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
$result = @($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_});
Write-Host "Invalid parameters: $(ConvertTo-Json $result)";
@($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_}).Count | Should Be 0;
}
}
It "Has required parameters in template file existing in parameters file" -TestCases $Modules {
Param( $Module )
$requiredParametersInTemplateFile = (Get-Content "$($Module.Template)" `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Where-Object -FilterScript { -not ($_.Value.PSObject.Properties.Name -eq "defaultValue") } `
| Sort-Object -Property Name `
| ForEach-Object Name
ForEach ( $Parameter in $Module.Parameters ) {
$allParametersInParametersFile = (Get-Content $Parameter `
| ConvertFrom-Json -ErrorAction SilentlyContinue).Parameters.PSObject.Properties `
| Sort-Object -Property Name `
| ForEach-Object Name
@($requiredParametersInTemplateFile| Where-Object {$allParametersInParametersFile -notcontains $_}).Count | Should Be 0;
}
}
}
}
#endregion
}

Просмотреть файл

@ -0,0 +1,56 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"virtualMachineScaleSetsName": {
"value": "adds"
},
"virtualMachineScaleSetsSku": {
"value": {
"name": "SKUName",
"tier": "Standard",
"capacity": 5
}
},
"virtualMachineScaleSetsOSImage": {
"value": {
"offer": "WindowsServer",
"publisher": "MicrosoftWindowsServer",
"sku": "2016-Datacenter"
}
},
"virtualMachineScaleSetsOSType": {
"value": "Windows"
},
"workspaceId": {
"value": "00000000-0000-0000-0000-000000000000"
},
"logAnalyticsWorkspacePrimarySharedKey": {
"value": ""
},
"diagnosticsStorageAccountName": {
"value": "contoso-diag-storage"
},
"diagnosticsStorageAccountSasToken": {
"value": ""
},
"artifactsStorageAccountName": {
"value": "contoso-diag-storage"
},
"artifactsStorageAccountSasKey": {
"value": ""
},
"vNetId": {
"value": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourceGroup/providers/Microsoft.Network/virtualNetworks/contoso-vnet-example"
},
"subnetName": {
"value": "sharedsvcs"
},
"adminUsername": {
"value": "contoso"
},
"adminPassword": {
"value": "password"
}
}
}

Просмотреть файл

@ -0,0 +1,787 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"virtualMachineScaleSetsName": {
"type": "string",
"minLength": 1,
"maxLength": 13,
"metadata": {
"description": "Required. Name for the ADDS VMs"
}
},
"virtualMachineScaleSetsSku": {
"type": "object",
"metadata": {
"description": "Required. Object containing the VMSS Sku, the object must have the following format: { 'name': 'SKUName', 'tier': 'Standard | Basic', 'capacity': 'Instance count' }"
}
},
"virtualMachineScaleSetsOSImage": {
"type": "object",
"metadata": {
"description": "Required. OS image used for VMSS"
}
},
"virtualMachineScaleSetsUpgradePolicy": {
"type": "string",
"defaultValue": "Manual",
"allowedValues": [
"Manual",
"Automatic"
],
"metadata": {
"description": "Optional. The upgrade policy of a VMSS, if Manual is specified, you control the application of updates to virtual machines in the scale set. You do this by using the manualUpgrade action. When Automatic is set, All virtual machines in the scale set are automatically updated at the same time. - Automatic, Manual, Rolling."
}
},
"virtualMachineScaleSetsRollingUpgradePolicy": {
"type": "object",
"defaultValue": {},
"metadata": {
"description": "Optional. The rolling upgrade policy of a VMSS, required if virtualMachineScaleSetsUpgradePolicy is set to Automatic and you want to perform rolling updates."
}
},
"virtualMachineScaleSetsAutomaticOSUpgradePolicy": {
"type": "object",
"defaultValue": {},
"metadata": {
"description": "Optional. The rolling upgrade policy of a VMSS, required if virtualMachineScaleSetsUpgradePolicy is set to Automatic and you want to perform automatic updates."
}
},
"virtualMachineScaleSetsOSType": {
"type": "string",
"allowedValues": [
"Windows",
"Linux"
],
"metadata": {
"description": "Required. OS type used for the VMs"
}
},
"virtualMachineScaleSetsDataDisks": {
"type": "array",
"defaultValue": [],
"metadata": {
"description": "Optional. Array of objects with the following expected format: [{ 'size': 120 }, { 'size': 130 }], this array indicates that two data disks will be created."
}
},
"virtualMachineScaleSetsPrivateIPAddressVersion": {
"type": "string",
"defaultValue": "IPv4",
"allowedValues": [
"IPv4",
"IPv6"
],
"metadata": {
"description": "Optional. Represents whether the specific ipconfiguration is IPv4 or IPv6"
}
},
"loadBalancerBackendPoolId": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Optional. Represents a Load Balancer backend pool resource identifier, if left blank, no Load Balancer will be associated to the VMSS"
}
},
"customData": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format."
}
},
"workspaceId": {
"type": "string",
"metadata": {
"description": "Required. WorkspaceId or CustomerId value of OMS. This value is referenced in OMS VM Extension"
}
},
"logAnalyticsWorkspacePrimarySharedKey": {
"type": "securestring",
"metadata": {
"description": "Required. WorkspaceKey value of OMS. This value is referenced in OMS VM Extension"
}
},
"diagnosticsStorageAccountName": {
"type": "string",
"metadata": {
"description": "Required. Storage account used to store diagnostic information"
}
},
"diagnosticsStorageAccountSasToken": {
"type": "securestring",
"metadata": {
"description": "Required. Diagnostic Storage Account SAS token"
}
},
"artifactsStorageAccountName": {
"type": "securestring",
"metadata": {
"description": "Required. Default storage account name. Storage account that contains output parameters and common scripts"
}
},
"artifactsStorageAccountSasKey": {
"type": "securestring",
"metadata": {
"description": "Required. Shared Access Signature Key used to download custom scripts"
}
},
"vNetId": {
"type": "string",
"metadata": {
"description": "Required. Shared services Virtual Network resource identifier"
}
},
"subnetName": {
"type": "string",
"metadata": {
"description": "Required. Name of Shared Services Subnet, this name is used to get the SubnetId"
}
},
"applicationSecurityGroupId": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Optional. Application Security Group to associate to the Network Interface. If left empty, the Network Interface would not be associated to any Application Security Group."
}
},
"adminUsername": {
"type": "securestring",
"metadata": {
"description": "Required. Domain user that has privileges to join a VM into a Domain"
}
},
"adminPassword": {
"type": "securestring",
"defaultValue": "",
"metadata": {
"description": "Optional. When specifying a Windows Virtual Machine, this value should be passed"
}
},
"sshPublicKey": {
"type": "securestring",
"defaultValue": "",
"metadata": {
"description": "Optional. SSH public key. When specifying a Linux Virtual Machine, this value should be passed. Linux VMs can be accessed via SSH public key only."
}
},
"proximityPlacementGroupsId": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Optional. If passed, the VMSS will be assigned to a Proximity Placement Groups."
}
},
"domainAdminUsername": {
"type": "securestring",
"defaultValue": "",
"metadata": {
"description": "Optional. Domain user that has privileges to join a VM into a Domain. If joinToDomain is set to true, this value becomes required."
}
},
"domainAdminPassword": {
"type": "securestring",
"defaultValue": "",
"metadata": {
"description": "Optional. Domain user that has privileges to join a VM into a Domain. If joinToDomain is set to true, this value becomes required."
}
},
"domainName": {
"type": "securestring",
"defaultValue": "",
"metadata": {
"description": "Optional. AD domain name. If joinToDomain is set to true, this value becomes required."
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Optional. Location for all resources."
}
}
},
"variables": {
"joinToDomain": "[and(not(empty(parameters('domainAdminUsername'))), not(empty(parameters('domainAdminPassword'))))]",
"applicationSecurityGroups": [
{
"id": "[parameters('applicationSecurityGroupId')]"
}
],
"proximityPlacementGroup": {
"id": "[parameters('proximityPlacementGroupsId')]"
},
"loadBalancerBackendPoolId": [
{
"id": "[parameters('loadBalancerBackendPoolId')]"
}
],
"linuxConfiguration": {
"disablePasswordAuthentication": true,
"ssh": {
"publicKeys": [
{
"path": "[concat('/home/', parameters('adminUsername'), '/.ssh/authorized_keys')]",
"keyData": "[parameters('sshPublicKey')]"
}
]
}
},
"subnetId": "[concat(parameters('vNetId'), '/subnets/', parameters('subnetName'))]",
"antimalwareExtensionName": "IaaSAntimalware",
"diagnosticsExtensionName": "IaaSDiagnostics",
"networkWatcherExtensionName": "NetworkWatcher",
"MMAExtensionName": "OMSExtension",
"tagPatching": "3rdSat7pm",
"DSCExtensionName": "DSCExtension",
"joinToDomainExtensionName": "JoinToDomainExtension",
"domainAndUsername": "[concat(parameters('domainName'), '\\', parameters('domainAdminUsername'))]"
},
"resources": [
{
"type": "Microsoft.Compute/virtualMachineScaleSets",
"apiVersion": "2019-03-01",
"location": "[parameters('location')]",
"name": "[parameters('virtualMachineScaleSetsName')]",
"tags": {
"computerName": "[parameters('virtualMachineScaleSetsName')]",
"UpdateManagement": "[variables('tagPatching')]"
},
"sku": {
"name": "[parameters('virtualMachineScaleSetsSku').name]",
"tier": "[parameters('virtualMachineScaleSetsSku').tier]",
"capacity": "[parameters('virtualMachineScaleSetsSku').capacity]"
},
"properties": {
"upgradePolicy": {
"mode": "[parameters('virtualMachineScaleSetsUpgradePolicy')]",
"rollingUpgradePolicy": "[parameters('virtualMachineScaleSetsRollingUpgradePolicy')]",
"automaticOSUpgradePolicy": "[parameters('virtualMachineScaleSetsAutomaticOSUpgradePolicy')]"
},
"virtualMachineProfile": {
"osProfile": {
"computerNamePrefix": "[parameters('virtualMachineScaleSetsName')]",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[if(equals(parameters('virtualMachineScaleSetsOSType'), 'Linux'), json('null'), parameters('adminPassword'))]",
"customData": "[if(empty(parameters('customData')), json('null'), base64(parameters('customData')))]",
"linuxConfiguration": "[if(equals(parameters('virtualMachineScaleSetsOSType'), 'Linux'), variables('linuxConfiguration'), json('null'))]"
},
"storageProfile": {
"imageReference": {
"publisher": "[parameters('virtualMachineScaleSetsOSImage').publisher]",
"offer": "[parameters('virtualMachineScaleSetsOSImage').offer]",
"sku": "[parameters('virtualMachineScaleSetsOSImage').sku]",
"version": "latest"
},
"osDisk": {
"caching": "ReadOnly",
"createOption": "FromImage",
"diskSizeGB": 256
},
"copy": [
{
"name": "dataDisks",
"count": "[length(parameters('virtualMachineScaleSetsDataDisks'))]",
"input": {
"lun": "[copyIndex('dataDisks')]",
"diskSizeGB": "[parameters('virtualMachineScaleSetsDataDisks')[copyIndex('dataDisks')].size]",
"createOption": "Empty",
"caching": "None"
}
}
]
},
"networkProfile": {
"networkInterfaceConfigurations": [
{
"name": "[concat(parameters('virtualMachineScaleSetsName'), '-nic')]",
"properties": {
"enableAcceleratedNetworking": true,
"primary": true,
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"subnet": {
"id": "[variables('subnetId')]"
},
"privateIPAddressVersion": "[parameters('virtualMachineScaleSetsPrivateIPAddressVersion')]",
"applicationSecurityGroups": "[if(empty(parameters('applicationSecurityGroupId')), json('null'), variables('applicationSecurityGroups'))]",
"loadBalancerBackendAddressPools": "[if(empty(parameters('loadBalancerBackendPoolId')), json('null'), variables('loadBalancerBackendPoolId'))]"
}
}
],
"enableIPForwarding": true
}
}
]
},
"diagnosticsProfile": {
"bootDiagnostics": {
"enabled": true,
"storageUri": "[concat('https://', parameters('diagnosticsStorageAccountName'), '.blob.core.windows.net/')]"
}
},
"extensionProfile": {
"extensions": [
{
"name": "[variables('MMAExtensionName')]",
"properties": {
"publisher": "Microsoft.EnterpriseCloud.Monitoring",
"type": "MicrosoftMonitoringAgent",
"typeHandlerVersion": "1.0",
"autoUpgradeMinorVersion": true,
"settings": {
"workspaceId": "[parameters('workspaceId')]"
},
"protectedSettings": {
"workspaceKey": "[parameters('logAnalyticsWorkspacePrimarySharedKey')]"
}
}
},
{
"name": "[variables('antimalwareExtensionName')]",
"properties": {
"publisher": "Microsoft.Azure.Security",
"type": "IaaSAntimalware",
"typeHandlerVersion": "1.5",
"autoUpgradeMinorVersion": true,
"settings": {
"AntimalwareEnabled": true,
"RealtimeProtectionEnabled": "true",
"ScheduledScanSettings": {
"isEnabled": "true",
"scanType": "Quick",
"day": "7",
"time": "120"
}
}
}
},
{
"name": "[variables('diagnosticsExtensionName')]",
"properties": {
"publisher": "Microsoft.Azure.Diagnostics",
"type": "IaaSDiagnostics",
"typeHandlerVersion": "1.5",
"autoUpgradeMinorVersion": true,
"settings": {
"StorageAccount": "[parameters('diagnosticsStorageAccountName')]",
"StorageType": "Blob",
"WadCfg": {
"DiagnosticMonitorConfiguration": {
"overallQuotaInMB": 5120,
"Metrics": {
"resourceId": "[resourceId('Microsoft.Compute/virtualMachineScaleSets', parameters('virtualMachineScaleSetsName'))]",
"MetricAggregation": [
{
"scheduledTransferPeriod": "PT1H"
},
{
"scheduledTransferPeriod": "PT1M"
}
]
},
"DiagnosticInfrastructureLogs": {
"scheduledTransferLogLevelFilter": "Error"
},
"PerformanceCounters": {
"scheduledTransferPeriod": "PT1M",
"PerformanceCounterConfiguration": [
{
"counterSpecifier": "\\Processor Information(_Total)\\% Processor Time",
"unit": "Percent",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Processor Information(_Total)\\% Privileged Time",
"unit": "Percent",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Processor Information(_Total)\\% User Time",
"unit": "Percent",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Processor Information(_Total)\\Processor Frequency",
"unit": "Count",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\System\\Processes",
"unit": "Count",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Process(_Total)\\Thread Count",
"unit": "Count",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Process(_Total)\\Handle Count",
"unit": "Count",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\System\\System Up Time",
"unit": "Count",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\System\\Context Switches/sec",
"unit": "CountPerSecond",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\System\\Processor Queue Length",
"unit": "Count",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Memory\\% Committed Bytes In Use",
"unit": "Percent",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Memory\\Available Bytes",
"unit": "Bytes",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Memory\\Committed Bytes",
"unit": "Bytes",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Memory\\Cache Bytes",
"unit": "Bytes",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Memory\\Pool Paged Bytes",
"unit": "Bytes",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Memory\\Pool Nonpaged Bytes",
"unit": "Bytes",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Memory\\Pages/sec",
"unit": "CountPerSecond",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Memory\\Page Faults/sec",
"unit": "CountPerSecond",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Process(_Total)\\Working Set",
"unit": "Count",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Process(_Total)\\Working Set - Private",
"unit": "Count",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\LogicalDisk(_Total)\\% Disk Time",
"unit": "Percent",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\LogicalDisk(_Total)\\% Disk Read Time",
"unit": "Percent",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\LogicalDisk(_Total)\\% Disk Write Time",
"unit": "Percent",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\LogicalDisk(_Total)\\% Idle Time",
"unit": "Percent",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\LogicalDisk(_Total)\\Disk Bytes/sec",
"unit": "BytesPerSecond",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\LogicalDisk(_Total)\\Disk Read Bytes/sec",
"unit": "BytesPerSecond",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\LogicalDisk(_Total)\\Disk Write Bytes/sec",
"unit": "BytesPerSecond",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\LogicalDisk(_Total)\\Disk Transfers/sec",
"unit": "BytesPerSecond",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\LogicalDisk(_Total)\\Disk Reads/sec",
"unit": "BytesPerSecond",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\LogicalDisk(_Total)\\Disk Writes/sec",
"unit": "BytesPerSecond",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer",
"unit": "Count",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\LogicalDisk(_Total)\\Avg. Disk sec/Read",
"unit": "Count",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\LogicalDisk(_Total)\\Avg. Disk sec/Write",
"unit": "Count",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\LogicalDisk(_Total)\\Avg. Disk Queue Length",
"unit": "Count",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length",
"unit": "Count",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length",
"unit": "Count",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\LogicalDisk(_Total)\\% Free Space",
"unit": "Percent",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\LogicalDisk(_Total)\\Free Megabytes",
"unit": "Count",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Network Interface(*)\\Bytes Total/sec",
"unit": "BytesPerSecond",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Network Interface(*)\\Bytes Sent/sec",
"unit": "BytesPerSecond",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Network Interface(*)\\Bytes Received/sec",
"unit": "BytesPerSecond",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Network Interface(*)\\Packets/sec",
"unit": "BytesPerSecond",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Network Interface(*)\\Packets Sent/sec",
"unit": "BytesPerSecond",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Network Interface(*)\\Packets Received/sec",
"unit": "BytesPerSecond",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Network Interface(*)\\Packets Outbound Errors",
"unit": "Count",
"sampleRate": "PT60S"
},
{
"counterSpecifier": "\\Network Interface(*)\\Packets Received Errors",
"unit": "Count",
"sampleRate": "PT60S"
}
]
},
"WindowsEventLog": {
"scheduledTransferPeriod": "PT1M",
"DataSource": [
{
"name": "Application!*[System[(Level = 1 or Level = 2 or Level = 3)]]"
},
{
"name": "Security!*[System[band(Keywords,4503599627370496)]]"
},
{
"name": "System!*[System[(Level = 1 or Level = 2 or Level = 3)]]"
}
]
}
}
}
},
"protectedSettings": {
"storageAccountName": "[parameters('diagnosticsStorageAccountName')]",
"storageAccountSasToken": "[parameters('diagnosticsStorageAccountSasToken')]",
"storageAccountEndPoint": "https://core.windows.net"
}
}
},
{
"name": "[variables('networkWatcherExtensionName')]",
"properties": {
"publisher": "Microsoft.Azure.NetworkWatcher",
"type": "NetworkWatcherAgentWindows",
"typeHandlerVersion": "1.4",
"autoUpgradeMinorVersion": true
}
},
{
"name": "[variables('DSCExtensionName')]",
"properties": {
"publisher": "Microsoft.Powershell",
"type": "DSC",
"typeHandlerVersion": "2.9",
"autoUpgradeMinorVersion": true,
"settings": {
"configuration": {
"url": "[concat('https://', parameters('artifactsStorageAccountName'), '.blob.core.windows.net/scripts/Windows/formatDataDisks.zip')]",
"script": "formatDisk.ps1",
"function": "FormatDisk"
},
"configurationArguments": {
"DataDisks": "[string(parameters('virtualMachineScaleSetsDataDisks'))]"
}
},
"protectedSettings": {
"configurationUrlSasToken": "[concat('?', parameters('artifactsStorageAccountSasKey'))]"
}
}
}
]
}
},
"overprovision": true,
"platformFaultDomainCount": 2,
"proximityPlacementGroup": "[if(empty(parameters('proximityPlacementGroupsId')), json('null'), variables('proximityPlacementGroup'))]"
},
"resources": []
},
{
"type": "Microsoft.Compute/virtualMachineScaleSets/extensions",
"apiVersion": "2019-03-01",
"name": "[concat(parameters('virtualMachineScaleSetsName'), '/', variables('joinToDomainExtensionName'))]",
"condition": "[variables('joinToDomain')]",
"location": "[parameters('location')]",
"properties": {
"publisher": "Microsoft.Compute",
"type": "JsonADDomainExtension",
"typeHandlerVersion": "1.3",
"settings": {
"Name": "[parameters('domainName')]",
"OUPath": "",
"User": "[variables('domainAndUsername')]",
"Restart": "true",
"Options": 3
},
"protectedsettings": {
"Password": "[parameters('domainAdminPassword')]"
}
}
},
{
"type": "Microsoft.Insights/autoscaleSettings",
"apiVersion": "2015-04-01",
"name": "[concat(parameters('virtualMachineScaleSetsName'), '-cpuautoscale')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.Compute/virtualMachineScaleSets/', parameters('virtualMachineScaleSetsName'))]"
],
"properties": {
"name": "[concat(parameters('virtualMachineScaleSetsName'), '-cpuautoscale')]",
"targetResourceUri": "[concat('/subscriptions/',subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Compute/virtualMachineScaleSets/', parameters('virtualMachineScaleSetsName'))]",
"enabled": true,
"profiles": [
{
"name": "Profile1",
"capacity": {
"minimum": "1",
"maximum": "10",
"default": "1"
},
"rules": [
{
"metricTrigger": {
"metricName": "Percentage CPU",
"metricNamespace": "",
"metricResourceUri": "[concat('/subscriptions/',subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Compute/virtualMachineScaleSets/', parameters('virtualMachineScaleSetsName'))]",
"timeGrain": "PT1M",
"statistic": "Average",
"timeWindow": "PT5M",
"timeAggregation": "Average",
"operator": "GreaterThan",
"threshold": 50
},
"scaleAction": {
"direction": "Increase",
"type": "ChangeCount",
"value": "1",
"cooldown": "PT5M"
}
},
{
"metricTrigger": {
"metricName": "Percentage CPU",
"metricNamespace": "",
"metricResourceUri": "[concat('/subscriptions/',subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Compute/virtualMachineScaleSets/', parameters('virtualMachineScaleSetsName'))]",
"timeGrain": "PT1M",
"statistic": "Average",
"timeWindow": "PT5M",
"timeAggregation": "Average",
"operator": "LessThan",
"threshold": 30
},
"scaleAction": {
"direction": "Decrease",
"type": "ChangeCount",
"value": "1",
"cooldown": "PT5M"
}
}
]
}
]
}
}
],
"outputs": {
"virtualMachineScaleSetsName": {
"type": "string",
"value": "[parameters('virtualMachineScaleSetsName')]"
},
"virtualMachineScaleSetsResourceId": {
"type": "string",
"value": "[resourceId('Microsoft.Compute/virtualMachineScaleSets', parameters('virtualMachineScaleSetsName'))]"
},
"virtualMachineScaleSetsResourceGroup": {
"type": "string",
"value": "[resourceGroup().name]"
}
}
}

Просмотреть файл

@ -0,0 +1,54 @@
# Active Directory
This template deploys Active Directory Domain Services.
## Resources
- Microsoft.Compute/availabilitySets
- Microsoft.Network/networkInterfaces
- Microsoft.Compute/virtualMachines
- Microsoft.Compute/virtualMachines/extensions
- Microsoft.Compute/virtualMachines/providers/guestConfigurationAssignments
## Parameters
| Parameter Name | Default Value | Description |
| :- | :- | :- |
| `virtualMachineName` | | Required. Name for the Active Directory VMs
| `virtualMachineSize` | `Standard_DS2_v2` | Optional. Size of the Active Directory VMs
| `virtualMachineOSImage` | | Required. OS image used for the Active Directory VMs| `artifactsStorageAccountSasKey` | | Required. Shared Access Signature Key used to download custom scripts
| `artifactsStorageAccountName` | | Required. Default storage account name. Storage account that contains output parameters and common scripts
| `artifactsStorageAccountKey` | | Required. Default storage account Key. Storage account that contains output parameters and common scripts
| `workspaceId` | | Required. WorkspaceId or CustomerId value of OMS. This value is referenced in OMS VM Extension
| `logAnalyticsWorkspacePrimarySharedKey` | | Required. WorkspaceKey value of OMS. This value is referenced in OMS VM Extension
| `diagnosticsStorageAccountName` | | Required. Storage account used to store diagnostic information
| `diagnosticsStorageAccountSasToken` | | Required. Diagnostic Storage Account SAS token
| `adIpAddress` | | Required. IP address used as primary Domain Controller IP
| `vNetId` | | Required. Shared services Virtual Network resource identifier
| `domainControllerAsgId` | | Required. ASG associated to Domain Controllers
| `subnetName` | | Required. Name of Shared Services Subnet, this name is used to get the SubnetId
| `cloudZone` | | Required. Cloud Zone to be created, this is useful when using one way trust relationship
| `domainName` | | Required. AD domain name
| `adSitename` | | Required. On-premises Active Directory site name
| `keyVaultId` | `""` | Optional. AKV Resource Id
| `keyVaultURL` | `""` | Optional. AKV URL
| `adKeyEncryptionURL` | `""` | Optional. Active Directory AKV encryption key
| `domainAdminUsername` | | Required. Domain user that has privileges to join a VM into a Domain
| `domainAdminPassword` | | Required. Domain user that has privileges to join a VM into a Domain
## Outputs
| Output Name | Description |
| :- | :- |
| `adResourceGroup` | The Resource Group that was deployed to.
| `dnsServers` | DNS Server IP
| `adAvailabilitySetResourceId` | Active Directory Availability Set Resource Identifier
## Considerations
*N/A*
## Additional resources
- [Active Directory Domain Services](https://docs.microsoft.com/en-us/windows/desktop/ad/active-directory-domain-services)
- [Microsoft.Compute virtualMachines template reference](https://docs.microsoft.com/en-us/azure/templates/microsoft.compute/2019-03-01/virtualmachines)

Просмотреть файл

@ -0,0 +1,64 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"virtualMachineName": {
"value": "adds"
},
"virtualMachineSize": {
"value": "Standard_DS2_v2"
},
"virtualMachineOSImage": {
"value": {
"offer": "WindowsServer",
"publisher": "MicrosoftWindowsServer",
"sku": "2016-Datacenter"
}
},
"virtualMachineOSType": {
"value": "Linux"
},
"workspaceId": {
"value": "00000000-0000-0000-0000-000000000000"
},
"logAnalyticsWorkspaceId": {
"value": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourceGroup/providers/Microsoft.OperationalInsights/workspaces/contoso-example"
},
"logAnalyticsWorkspacePrimarySharedKey": {
"value": ""
},
"diagnosticsStorageAccountId": {
"value": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourceGroup/providers/Microsoft.Storage/storageAccounts/contosostrgexmpl"
},
"diagnosticsStorageAccountName": {
"value": "contoso-diag-storage"
},
"diagnosticsStorageAccountSasToken": {
"value": ""
},
"artifactsStorageAccountName": {
"value": "vdcstorage"
},
"artifactsStorageAccountKey": {
"value": ""
},
"artifactsStorageAccountSasKey": {
"value": ""
},
"vNetId": {
"value": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourceGroup/providers/Microsoft.Network/virtualNetworks/contoso-vnet-example"
},
"subnetName": {
"value": "sharedsvcs"
},
"adminUsername": {
"value": "contoso"
},
"sshPublicKey": {
"value": "password"
},
"enablePublicIP": {
"value": true
}
}
}

Просмотреть файл

@ -10,9 +10,9 @@
},
"virtualMachineOSImage": {
"value": {
"offer": "WindowsServer",
"publisher": "MicrosoftWindowsServer",
"sku": "2016-Datacenter"
"publisher": "Canonical",
"offer": "UbuntuServer",
"sku": "18.04-LTS"
}
},
"virtualMachineOSType": {

Просмотреть файл

@ -133,7 +133,11 @@ Describe "Template: $template - Virtual Machine" -Tags Unit {
| Sort-Object -Property Name `
| ForEach-Object Name
$result = @($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_});
Write-Host "Invalid parameters: $(ConvertTo-Json $result)";
if ($result.Count -gt 0) {
Write-Host "Invalid parameters: $(ConvertTo-Json $result)"
}
@($allParametersInParametersFile| Where-Object {$allParametersInTemplateFile -notcontains $_}).Count | Should Be 0;
}
}
@ -153,7 +157,14 @@ Describe "Template: $template - Virtual Machine" -Tags Unit {
| Sort-Object -Property Name `
| ForEach-Object Name
@($requiredParametersInTemplateFile | Where-Object {$allParametersInParametersFile -notcontains $_}).Count | Should Be 0;
$invalidParameters = `
$requiredParametersInTemplateFile | Where-Object {$allParametersInParametersFile -notcontains $_}
if ($invalidParameters.Count -gt 0) {
Write-Host "Parameters not found: $(ConvertTo-Json $invalidParameters)"
}
$invalidParameters.Count | Should Be 0
}
}
}

Просмотреть файл

@ -0,0 +1,64 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"virtualMachineName": {
"value": "adds"
},
"virtualMachineSize": {
"value": "Standard_DS2_v2"
},
"virtualMachineOSImage": {
"value": {
"offer": "WindowsServer",
"publisher": "MicrosoftWindowsServer",
"sku": "2016-Datacenter"
}
},
"virtualMachineOSType": {
"value": "Windows"
},
"workspaceId": {
"value": "00000000-0000-0000-0000-000000000000"
},
"logAnalyticsWorkspaceId": {
"value": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourceGroup/providers/Microsoft.OperationalInsights/workspaces/contoso-example"
},
"logAnalyticsWorkspacePrimarySharedKey": {
"value": ""
},
"diagnosticsStorageAccountId": {
"value": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourceGroup/providers/Microsoft.Storage/storageAccounts/contosostrgexmpl"
},
"diagnosticsStorageAccountName": {
"value": "contoso-diag-storage"
},
"diagnosticsStorageAccountSasToken": {
"value": ""
},
"artifactsStorageAccountName": {
"value": "vdcstorage"
},
"artifactsStorageAccountKey": {
"value": ""
},
"artifactsStorageAccountSasKey": {
"value": ""
},
"vNetId": {
"value": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourceGroup/providers/Microsoft.Network/virtualNetworks/contoso-vnet-example"
},
"subnetName": {
"value": "sharedsvcs"
},
"adminUsername": {
"value": "contoso"
},
"adminPassword": {
"value": "password"
},
"enablePublicIP": {
"value": true
}
}
}

Просмотреть файл

@ -0,0 +1,70 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"virtualMachineName": {
"value": "adds"
},
"virtualMachineSize": {
"value": "Standard_DS2_v2"
},
"virtualMachineOSImage": {
"value": {
"offer": "WindowsServer",
"publisher": "MicrosoftWindowsServer",
"sku": "2016-Datacenter"
}
},
"virtualMachineOSType": {
"value": "Windows"
},
"workspaceId": {
"value": "00000000-0000-0000-0000-000000000000"
},
"logAnalyticsWorkspaceId": {
"value": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourceGroup/providers/Microsoft.OperationalInsights/workspaces/contoso-example"
},
"logAnalyticsWorkspacePrimarySharedKey": {
"value": ""
},
"diagnosticsStorageAccountId": {
"value": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourceGroup/providers/Microsoft.Storage/storageAccounts/contosostrgexmpl"
},
"diagnosticsStorageAccountName": {
"value": "contoso-diag-storage"
},
"diagnosticsStorageAccountSasToken": {
"value": ""
},
"artifactsStorageAccountName": {
"value": "vdcstorage"
},
"artifactsStorageAccountKey": {
"value": ""
},
"artifactsStorageAccountSasKey": {
"value": ""
},
"vNetId": {
"value": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourceGroup/providers/Microsoft.Network/virtualNetworks/contoso-vnet-example"
},
"subnetName": {
"value": "sharedsvcs"
},
"adminUsername": {
"value": "contoso"
},
"adminPassword": {
"value": "password"
},
"domainAdminUsername": {
"value": "contoso"
},
"domainAdminPassword": {
"value": "password"
},
"domainName": {
"value": "contoso.com"
}
}
}

Просмотреть файл

@ -3,59 +3,74 @@
"contentVersion": "1.0.0.0",
"parameters": {
"virtualMachineName": {
"value": "adds"
},
"virtualMachineSize": {
"value": "Standard_DS2_v2"
},
"virtualMachineOSImage": {
"value": {
"offer": "WindowsServer",
"publisher": "MicrosoftWindowsServer",
"sku": "2016-Datacenter"
}
},
"virtualMachineOSType": {
"value": "Windows"
},
"workspaceId": {
"value": "00000000-0000-0000-0000-000000000000"
},
"logAnalyticsWorkspaceId": {
"value": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourceGroup/providers/Microsoft.OperationalInsights/workspaces/contoso-example"
"value": "joined"
},
"logAnalyticsWorkspacePrimarySharedKey": {
"value": ""
},
"diagnosticsStorageAccountId": {
"value": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourceGroup/providers/Microsoft.Storage/storageAccounts/contosostrgexmpl"
"workspaceId": {
"value": "00000000-0000-0000-0000-000000000000"
},
"domainName": {
"value": "fontoso.com"
},
"virtualMachineOSType": {
"value": "Windows"
},
"logAnalyticsWorkspaceId": {
"value": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cntsrg/providers/Microsoft.OperationalInsights/workspaces/shrdsvcs-la"
},
"adminUsername": {
"value": "admin-user"
},
"virtualMachineOSImage": {
"value": {
"sku": "2016-Datacenter",
"publisher": "MicrosoftWindowsServer",
"offer": "WindowsServer"
}
},
"vNetId": {
"value": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/shrdsvcs-network-rg/providers/Microsoft.Network/virtualNetworks/shrdsvcs-vnet"
},
"diagnosticsStorageAccountName": {
"value": "contoso-diag-storage"
},
"diagnosticsStorageAccountSasToken": {
"value": ""
},
"artifactsStorageAccountName": {
"value": "vdcstorage"
"value": "shrdsvcsdiag01"
},
"artifactsStorageAccountKey": {
"value": ""
},
"artifactsStorageAccountName": {
"value": "cstmartfcts01"
},
"artifactsStorageAccountSasKey": {
"value": ""
},
"vNetId": {
"value": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourceGroup/providers/Microsoft.Network/virtualNetworks/contoso-vnet-example"
"applicationSecurityGroupId": {
"value": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/shrdsvcs-network-rg/providers/Microsoft.Network/applicationSecurityGroups/jumpbox-asg"
},
"domainAdminPassword": {
"value": "foo"
},
"virtualMachineSize": {
"value": "Standard_DS2_v2"
},
"diagnosticsStorageAccountSasToken": {
"value": ""
},
"subnetName": {
"value": "sharedsvcs"
"value": "shrdsvcs"
},
"adminUsername": {
"value": "contoso"
"domainAdminUsername": {
"value": "fontoso"
},
"virtualMachineCount": {
"value": 1
},
"diagnosticsStorageAccountId": {
"value": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/shrdsvcs-diagnostics-rg/providers/Microsoft.Storage/storageAccounts/shrdsvcsdiag01"
},
"adminPassword": {
"value": "password"
"value": "foo"
}
}
}

Просмотреть файл

@ -7,14 +7,14 @@
"minLength": 1,
"maxLength": 13,
"metadata": {
"description": "Required. Name for the ADDS VMs"
"description": "Required. Name for the VMs"
}
},
"virtualMachineSize": {
"type": "string",
"defaultValue": "Standard_DS2_v2",
"metadata": {
"description": "Optional. Size of the ADDS VMs"
"description": "Optional. Size of the VMs"
}
},
"virtualMachineOSImage": {
@ -160,7 +160,7 @@
"adminUsername": {
"type": "securestring",
"metadata": {
"description": "Required. Domain user that has privileges to join a VM into a Domain"
"description": "Required. Administrator username"
}
},
"adminPassword": {
@ -177,15 +177,51 @@
"description": "Optional. SSH public key. When specifying a Linux Virtual Machine, this value should be passed. Linux VMs can be accessed via SSH public key only."
}
},
"proximityPlacementGroupsId": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Optional. If passed, the VM will be assigned to a Proximity Placement Groups."
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Optional. Location for all resources."
}
},
"enablePublicIP": {
"type": "bool",
"defaultValue": false,
"metadata": {
"description": "Optional. Enables the creation of a Public IP and assigns it to the Network Interface."
}
},
"domainAdminUsername": {
"type": "securestring",
"defaultValue": "",
"metadata": {
"description": "Optional. Domain user that has privileges to join a VM into a Domain. If joinToDomain is set to true, this value becomes required."
}
},
"domainAdminPassword": {
"type": "securestring",
"defaultValue": "",
"metadata": {
"description": "Optional. Domain user that has privileges to join a VM into a Domain. If joinToDomain is set to true, this value becomes required."
}
},
"domainName": {
"type": "securestring",
"defaultValue": "",
"metadata": {
"description": "Optional. AD domain name. If joinToDomain is set to true, this value becomes required."
}
}
},
"variables": {
"joinToDomain": "[and(not(empty(parameters('domainAdminUsername'))), not(empty(parameters('domainAdminPassword'))))]",
"uniqueString": "[uniqueString(subscription().id, resourceGroup().id, concat(parameters('virtualMachineName'), '-vm'))]",
"subnetName": "[parameters('subnetName')]",
"availabilitySetName": "vm-availability-set",
@ -207,6 +243,9 @@
}
]
},
"proximityPlacementGroup": {
"id": "[parameters('proximityPlacementGroupsId')]"
},
"linuxConfiguration": {
"disablePasswordAuthentication": true,
"ssh": {
@ -225,7 +264,7 @@
"MMAExtensionName": "OMSExtension",
"DSCExtensionName": "DSCExtension",
"tagPatching": "3rdSat7pm",
"windowsPasswordPoliciesExtensionName": "PwshExtension",
"PwshExtensionName": "PwshExtension",
"windowsDependencyExtensionName": "DependencyAgent",
"windowsDependencyExtensionPublisher": "Microsoft.Azure.Monitoring.DependencyAgent",
"windowsDependencyExtensionType": "DependencyAgentWindows",
@ -261,7 +300,8 @@
"input": "[resourceId('Microsoft.Compute/virtualMachines', concat(parameters('virtualMachineName'), copyIndex('vmResourceIds', parameters('virtualMachineOffset'))))]"
}
]
}
},
"artifactsStorageAccountSasToken": "[concat('?', parameters('artifactsStorageAccountSasKey'))]"
},
"resources": [
{
@ -279,6 +319,23 @@
"name": "Aligned"
}
},
{
"type": "Microsoft.Network/publicIPAddresses",
"apiVersion": "2018-08-01",
"name": "[concat(parameters('virtualMachineName'), copyIndex(parameters('virtualMachineOffset')), '-pip')]",
"location": "[parameters('location')]",
"condition": "[parameters('enablePublicIP')]",
"copy": {
"name": "pipLoop",
"count": "[parameters('virtualMachineCount')]"
},
"sku": {
"name": "Standard"
},
"properties": {
"publicIPAllocationMethod": "Static"
}
},
{
"type": "Microsoft.Network/networkInterfaces",
"apiVersion": "2017-09-01",
@ -287,6 +344,9 @@
"name": "nicLoop",
"count": "[parameters('virtualMachineCount')]"
},
"dependsOn": [
"pipLoop"
],
"name": "[concat(parameters('virtualMachineName'), copyIndex(parameters('virtualMachineOffset')), '-nic')]",
"properties": {
"ipConfigurations": [
@ -294,6 +354,7 @@
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "[if(empty(parameters('vmIPAddress')), 'Dynamic', 'Static')]",
"publicIPAddress": "[if(not(parameters('enablePublicIP')), json('null'), json(concat('{\"id\":\"', resourceId('Microsoft.Network/publicIPAddresses', concat(parameters('virtualMachineName'), copyIndex(parameters('virtualMachineOffset')), '-pip')),'\"}')))]",
"privateIPAddress": "[if(empty(parameters('vmIPAddress')), json('null'), vdc.nextIP(parameters('vmIPAddress'), copyIndex()))]",
"subnet": {
"id": "[variables('subnetId')]"
@ -334,7 +395,7 @@
},
{
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "2017-03-30",
"apiVersion": "2018-06-01",
"location": "[parameters('location')]",
"name": "[concat(parameters('virtualMachineName'), copyIndex(parameters('virtualMachineOffset')))]",
"copy": {
@ -347,10 +408,12 @@
"UpdateManagement": "[variables('tagPatching')]"
},
"dependsOn": [
"nicDiagnosticLoop"
"nicDiagnosticLoop",
"[variables('availabilitySetName')]"
],
"properties": {
"availabilitySet": "[if(not(variables('availabilityZonesEnabled')), variables('availabilitySet'), json('null'))]",
"proximityPlacementGroup": "[if(empty(parameters('proximityPlacementGroupsId')), json('null'), variables('proximityPlacementGroup'))]",
"osProfile": {
"computerName": "[concat(parameters('virtualMachineName'), copyIndex(parameters('virtualMachineOffset')))]",
"adminUsername": "[parameters('adminUsername')]",
@ -378,8 +441,7 @@
{
"name": "dataDisks",
"count": "[length(parameters('virtualMachineDataDisks'))]",
"input":
{
"input": {
"lun": "[copyIndex('dataDisks')]",
"name": "[replace(toLower(substring(concat(parameters('virtualMachineName'), copyIndex('vmLoop', parameters('virtualMachineOffset')), '-dsk', copyindex('dataDisks', parameters('virtualMachineOffset')), '-', replace(concat(variables('uniqueString'), variables('uniqueString')), '-', '')), 0, 30)), '-', '')]",
"diskSizeGB": "[parameters('virtualMachineDataDisks')[copyIndex('dataDisks')].size]",
@ -476,6 +538,35 @@
}
}
},
{
"type": "extensions",
"name": "[variables('DSCExtensionName')]",
"apiVersion": "2017-03-30",
"location": "[parameters('location')]",
"condition": "[equals(parameters('virtualMachineOSType'), 'Windows')]",
"dependsOn": [
"[resourceId('Microsoft.Compute/virtualMachines', concat(parameters('virtualMachineName'), copyIndex(parameters('virtualMachineOffset'))))]"
],
"properties": {
"publisher": "Microsoft.Powershell",
"type": "DSC",
"typeHandlerVersion": "2.9",
"autoUpgradeMinorVersion": true,
"settings": {
"configuration": {
"url": "[concat('https://', parameters('artifactsStorageAccountName'), '.blob.core.windows.net/scripts/Windows/formatDataDisks.zip')]",
"script": "formatDisk.ps1",
"function": "FormatDisk"
},
"configurationArguments": {
"DataDisks": "[string(parameters('virtualMachineDataDisks'))]"
}
},
"protectedSettings": {
"configurationUrlSasToken": "[variables('artifactsStorageAccountSasToken')]"
}
}
},
{
"type": "extensions",
"name": "[variables('diagnosticsExtensionName')]",
@ -787,7 +878,7 @@
},
{
"type": "extensions",
"name": "[variables('windowsPasswordPoliciesExtensionName')]",
"name": "[variables('PwshExtensionName')]",
"apiVersion": "2017-03-30",
"location": "[parameters('location')]",
"condition": "[equals(parameters('virtualMachineOSType'), 'Windows')]",
@ -819,7 +910,7 @@
"condition": "[equals(parameters('virtualMachineOSType'), 'Windows')]",
"dependsOn": [
"[resourceId('Microsoft.Compute/virtualMachines', concat(parameters('virtualMachineName'), copyIndex(parameters('virtualMachineOffset'))))]",
"[variables('windowsPasswordPoliciesExtensionName')]"
"[variables('PwshExtensionName')]"
],
"properties": {
"publisher": "[variables('windowsDependencyExtensionPublisher')]",
@ -1801,35 +1892,57 @@
]
},
{
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "[concat(parameters('virtualMachineName'), copyIndex(parameters('virtualMachineOffset')), '/', variables('DSCExtensionName'))]",
"apiVersion": "2017-03-30",
"location": "[parameters('location')]",
"condition": "[not(empty(parameters('virtualMachineDataDisks')))]",
"name": "[concat('JoinToDomain-VM', copyIndex(parameters('virtualMachineOffset')))]",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2016-09-01",
"condition": "[and(equals(parameters('virtualMachineOSType'), 'Windows'), variables('joinToDomain'))]",
"dependsOn": [
"vmLoop"
],
"copy": {
"name": "vmFormatDataDiskLoop",
"name": "vmWindowsJoinDomainLoop",
"count": "[parameters('virtualMachineCount')]"
},
"properties": {
"publisher": "Microsoft.Powershell",
"type": "DSC",
"typeHandlerVersion": "2.9",
"autoUpgradeMinorVersion": true,
"settings": {
"configuration": {
"url": "[concat('https://', parameters('artifactsStorageAccountName'), '.blob.core.windows.net/scripts/Windows/formatDataDisks.zip')]",
"script": "formatDisk.ps1",
"function": "FormatDisk"
},
"configurationArguments": {
"DataDisks": "[string(parameters('virtualMachineDataDisks'))]"
}
},
"protectedSettings": {
"configurationUrlSasToken": "[concat('?', parameters('artifactsStorageAccountSasKey'))]"
"mode": "Incremental",
"template":{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"resources": [
{
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "[concat(parameters('virtualMachineName'), copyIndex(parameters('virtualMachineOffset')), '/', variables('DSCExtensionName'))]",
"apiVersion": "2017-03-30",
"location": "[parameters('location')]",
"properties": {
"publisher": "Microsoft.Powershell",
"type": "DSC",
"typeHandlerVersion": "2.9",
"autoUpgradeMinorVersion": true,
"settings": {
"configuration": {
"url": "[concat('https://', parameters('artifactsStorageAccountName'), '.blob.core.windows.net/scripts/Windows/joinComputerToDomain.zip')]",
"script": "joinComputerToDomain.ps1",
"function": "JoinComputerToDomain"
},
"configurationArguments": {
"DomainName": "[parameters('domainName')]",
"ServerName": "[concat(parameters('virtualMachineName'), copyIndex(parameters('virtualMachineOffset')))]"
}
},
"protectedSettings": {
"configurationUrlSasToken": "[variables('artifactsStorageAccountSasToken')]",
"configurationArguments": {
"AdminCreds": {
"UserName": "[parameters('domainAdminUsername')]",
"Password": "[parameters('domainAdminPassword')]"
}
}
}
}
}
]
}
}
}

Просмотреть файл

@ -218,9 +218,10 @@ Class Initialize {
# Let's check if the life of the sas token expires within an hour
# if it does, let's get a new sas token
if($storageAccountDetails.ExpiryTime -le `
((Get-Date) - $oneHourDuration)) {
if(($storageAccountDetails.ExpiryTime - (Get-Date)) -le $oneHourDuration) {
Write-Debug "Obtaining new SAS Token, previous expired"
# Setting AZ context to be able to retrieve the proper
# SAS token, there are situations where the toolkit
# subscription is different than the one from the
@ -234,6 +235,7 @@ Class Initialize {
$this.dataStoreName,
$this.dataStoreResourceGroupName);
Write-Debug "Sas token acquired, new expiriy time is: $($storageAccountDetails.ExpiryTime)"
$storageAccountDetails.StorageAccountSasToken = `
$sasToken.SASToken;
$storageAccountDetails.ExpiryTime = `
@ -275,17 +277,20 @@ Class Initialize {
[string] $storageAccountResourceGroup) {
try {
Write-Host "Creating a storage account: $storageAccountName in resource group: $storageAccountResourceGroup"
$storageAccountAccessKey = $null;
$storageAccountAccessKeys = `
(Get-AzStorageAccountKey `
-ResourceGroupName $this.dataStoreResourceGroupName `
-Name $this.dataStoreName).Value;
# Set SAS Token expiration of 2 hours
$twoHoursDuration = New-TimeSpan -Hours 3;
$expiryTime = (Get-Date) + $twoHoursDuration;
if($null -ne $storageAccountAccessKeys) {
Write-Host "Keys acquired successfully"
$storageAccountAccessKey = `
$storageAccountAccessKeys[0];

Просмотреть файл

@ -82,9 +82,8 @@ Class ModuleStateDataService: IModuleStateDataService {
$this.stateRepository.GetLatestDeploymentMapping($filters);
# If deploymentMapping is null, it means that there is no mapping found
if (!$deploymentMapping) {
Write-Debug "No state information found";
return $null;
if ($null -eq $deploymentMapping) {
throw "No state information found, make sure that the module definition: $moduleInstanceName in the deployment instance: $archetypeInstanceName was deployed.";
}
else {
# deployment mapping found, let's get the deployment outputs

Просмотреть файл

@ -365,6 +365,13 @@ Class AzureResourceManagerDeploymentService: IDeploymentService {
$tokenCache = $context.TokenCache;
$cacheItems = $tokenCache.ReadItems();
$accessToken = '';
# Let's filter based on management endpoint (resource
# management)
$cacheItems =
$cacheItems | `
Where-Object -Property "Resource" -Like "*management*"
$cacheItems | ForEach-Object {
# Cache Items object's TenantId is null when run in
# an AzDO Agent

Просмотреть файл

@ -6,7 +6,7 @@
[Parameter(Mandatory=$true)]
[string]
$DefinitionPath,
[Parameter(Mandatory=$true)]
[Parameter(Mandatory=$false)]
[string]
$ModuleConfigurationName,
[Parameter(Mandatory=$false)]
@ -49,7 +49,7 @@ Function New-Deployment {
[Parameter(Mandatory=$true)]
[string]
$DefinitionPath,
[Parameter(Mandatory=$true)]
[Parameter(Mandatory=$false)]
[string]
$ModuleConfigurationName,
[Parameter(Mandatory=$false)]
@ -108,322 +108,350 @@ Function New-Deployment {
-ArchetypeInstance $archetypeInstanceJson `
-ArchetypeInstanceName $ArchetypeInstanceName;
$moduleConfiguration = `
Get-ModuleConfiguration `
-ArchetypeInstanceJson $archetypeInstanceJson `
-ModuleConfigurationName $moduleConfigurationName `
-ArchetypeInstanceName $ArchetypeInstanceName `
-Operation @{ "False" = "deploy"; "True" = "validate"; }[$Validate.ToString()];;
$allModules = @()
if ($null -eq $moduleConfiguration) {
throw "Module configuration not found for module name: $moduleConfigurationName";
}
Write-Debug "Module instance is: $(ConvertTo-Json $moduleConfiguration)";
# Let's make sure we use the updated name
# There are instances when we have a module configuration updating an existing
# module configuration that was already deployed, in this case, let's use
# the name of the existing module configuration.
Write-Debug "Updating module instance name from $ModuleConfigurationName to $($moduleConfiguration.Name)";
$ModuleConfigurationName = `
$moduleConfiguration.Name;
$subscriptionInformation = $null;
$subscriptionInformation = `
Get-SubscriptionInformation `
-ArchetypeInstanceJson $archetypeInstanceJson `
-SubscriptionName $archetypeInstanceJson.Parameters.Subscription `
-ModuleConfiguration $moduleConfiguration;
if ($null -eq $subscriptionInformation) {
throw "Subscription: $($archetypeInstanceJson.Parameters.Subscription) not found";
}
# Let's get the current subscription context
$sub = Get-AzContext | Select-Object Subscription
# Do not change the subscription context if the operation is validate.
# This is because the script will expect the validation resource
# group to be present in all the subscriptions we are deploying.
[Guid]$subscriptionCheck = [Guid]::Empty;
[Guid]$tenantIdCheck = [Guid]::Empty;
if($null -ne $subscriptionInformation -and `
[Guid]::TryParse($subscriptionInformation.SubscriptionId, [ref]$subscriptionCheck) -and `
[Guid]::TryParse($subscriptionInformation.TenantId, [ref]$tenantIdCheck) -and `
$subscriptionCheck -ne [Guid]::Empty -and `
$tenantIdCheck -ne [Guid]::Empty -and
$subscriptionCheck -ne $sub.Subscription.Id) {
Write-Debug "Setting subscription context";
Set-SubscriptionContext `
-SubscriptionId $subscriptionInformation.SubscriptionId `
-TenantId $subscriptionInformation.TenantId;
}
# Let's attempt to get the Audit Id from cache
$auditCacheKey = `
"{0}_AuditId" -f `
$ArchetypeInstanceName;
Write-Debug "Audit Id cache key is: $auditCacheKey";
$auditId = `
Get-ItemFromCache `
-Key $auditCacheKey;
Write-Debug "Audit Id from cache is: $auditId"
# If no value is found, let's create
# deployment audit information and cache
# the auditId value
if ($null -eq $auditId) {
# Store deployment audit information
$auditInformation = `
Get-AzureDevOpsAuditEnvironmentVariables;
$auditId = `
New-DeploymentAuditInformation `
-BuildId $auditInformation.BuildId `
-BuildName $auditInformation.BuildName `
-CommitId $auditInformation.CommitId `
-CommitMessage $auditInformation.CommitMessage `
-CommitUsername $auditInformation.CommitUsername `
-BuildQueuedBy $auditInformation.BuildQueuedBy `
-ReleaseId $auditInformation.ReleaseId `
-ReleaseName $auditInformation.ReleaseName `
-ReleaseRequestedFor $auditInformation.ReleaseRequestedFor `
-TenantId @("",$subscriptionInformation.TenantId)[$null -ne $subscriptionInformation] `
-SubscriptionId @("", $subscriptionInformation.SubscriptionId)[$null -ne $subscriptionInformation] `
-ArchetypeInstance $archetypeInstanceJson `
-ArchetypeInstanceName $ArchetypeInstanceName `
-Validate:$($Validate.IsPresent);
Write-Debug "Audit trail created, Id: $auditId";
if ([string]::IsNullOrEmpty($ModuleConfigurationName)) {
Add-ItemToCache `
-Key $auditCacheKey `
-Value $auditId `
-Validate:$($Validate.IsPresent);
Write-Debug "Audit Id succesfully cached.";
}
$topologicalSortRootPath = `
Join-Path $rootPath -ChildPath 'TopologicalSort';
Invoke-Command -ScriptBlock { dotnet build $topologicalSortRootPath --configuration Release --output ./ }
# Runs a custom script only if Script property is present and
        # we are not in Validation mode
        if($null -ne $ModuleConfiguration.Script `
            -and `
           $null -ne $ModuleConfiguration.Script.Command) {
 
            # Orchestrate the deployment of Custom Scripts
            $result = `
                New-CustomScripts `
                    -ModuleConfiguration $moduleConfiguration `
                    -ArchetypeInstanceJson $archetypeInstanceJson `
-Validate:$($Validate.IsPresent);
 
            # Retrieve the results from the script deployment
            $resourceState = $result[0];
 
            # Did the ArchetypeInstanceJson change?
            if($null -ne $result[1]) {
                # Set the ArchetypeInstanceJson only if it is
                # modified by the custom script deployment
                $archetypeInstanceJson = $result[1];
 
                # Re-cache the ArchetypeInstanceJson
                Add-ItemToCache `
                    -Key $ArchetypeInstanceName `
                    -Value $archetypeInstanceJson `
-Validate:$($Validate.IsPresent);
            }     
$topologicalSortAssemblyPath = `
Join-Path $topologicalSortRootPath "TopologicalSort.dll"
Add-Type -Path $topologicalSortAssemblyPath
$graph = [VDC.Core.DirectedGraph]::new()
$orchestrationJson = `
ConvertTo-Json $archetypeInstanceJson.Orchestration.ModuleConfigurations
$graph.Generate($orchestrationJson)
$graph.DFS()
$graph.TopologicalSort | ForEach-Object { $allModules += $_.Name }
}
else {
$allModules += $ModuleConfigurationName
}
foreach($ModuleConfigurationName in $allModules) {
Write-Host "Deploying Module: $ModuleConfigurationName"
$moduleConfiguration = `
Get-ModuleConfiguration `
-ArchetypeInstanceJson $archetypeInstanceJson `
-ModuleConfigurationName $moduleConfigurationName `
-ArchetypeInstanceName $ArchetypeInstanceName `
-Operation @{ "False" = "deploy"; "True" = "validate"; }[$Validate.ToString()];;
# Let's get the module's template information first,
# this template will dictate if is a resource group or
# subscription deployment based on the template's schema
$moduleConfigurationDeploymentInformation = `
Get-DeploymentTemplateFileContents `
-DeploymentConfiguration $moduleConfiguration.Deployment `
-ModuleConfigurationsPath $archetypeInstanceJson.Orchestration.ModuleConfigurationsPath `
-WorkingDirectory $defaultWorkingDirectory;
if ($null -eq $moduleConfiguration) {
throw "Module configuration not found for module name: $moduleConfigurationName";
}
$moduleConfigurationDeploymentParameters = $null;
Write-Debug "Module instance is: $(ConvertTo-Json $moduleConfiguration)";
$isSubscriptionDeployment = $false;
# Let's make sure we use the updated name
# There are instances when we have a module configuration updating an existing
# module configuration that was already deployed, in this case, let's use
# the name of the existing module configuration.
Write-Debug "Updating module instance name from $ModuleConfigurationName to $($moduleConfiguration.Name)";
$ModuleConfigurationName = `
$moduleConfiguration.Name;
if($null -ne $moduleConfigurationDeploymentInformation) {
$subscriptionInformation = $null;
$subscriptionInformation = `
Get-SubscriptionInformation `
-ArchetypeInstanceJson $archetypeInstanceJson `
-SubscriptionName $archetypeInstanceJson.Parameters.Subscription `
-ModuleConfiguration $moduleConfiguration;
if ($null -eq $subscriptionInformation) {
throw "Subscription: $($archetypeInstanceJson.Parameters.Subscription) not found";
}
# Let's get the current subscription context
$sub = Get-AzContext | Select-Object Subscription
# Do not change the subscription context if the operation is validate.
# This is because the script will expect the validation resource
# group to be present in all the subscriptions we are deploying.
[Guid]$subscriptionCheck = [Guid]::Empty;
[Guid]$tenantIdCheck = [Guid]::Empty;
if($null -ne $subscriptionInformation -and `
[Guid]::TryParse($subscriptionInformation.SubscriptionId, [ref]$subscriptionCheck) -and `
[Guid]::TryParse($subscriptionInformation.TenantId, [ref]$tenantIdCheck) -and `
$subscriptionCheck -ne [Guid]::Empty -and `
$tenantIdCheck -ne [Guid]::Empty -and
$subscriptionCheck -ne $sub.Subscription.Id) {
$moduleConfigurationDeploymentTemplate = `
$moduleConfigurationDeploymentInformation.Template;
Write-Debug "Setting subscription context";
Set-SubscriptionContext `
-SubscriptionId $subscriptionInformation.SubscriptionId `
-TenantId $subscriptionInformation.TenantId;
}
# Let's attempt to get the Audit Id from cache
$auditCacheKey = `
"{0}_AuditId" -f `
$ArchetypeInstanceName;
Write-Debug "Audit Id cache key is: $auditCacheKey";
$auditId = `
Get-ItemFromCache `
-Key $auditCacheKey;
Write-Debug "Audit Id from cache is: $auditId"
# If no value is found, let's create
# deployment audit information and cache
# the auditId value
if ($null -eq $auditId) {
# Store deployment audit information
$auditInformation = `
Get-AzureDevOpsAuditEnvironmentVariables;
$auditId = `
New-DeploymentAuditInformation `
-BuildId $auditInformation.BuildId `
-BuildName $auditInformation.BuildName `
-CommitId $auditInformation.CommitId `
-CommitMessage $auditInformation.CommitMessage `
-CommitUsername $auditInformation.CommitUsername `
-BuildQueuedBy $auditInformation.BuildQueuedBy `
-ReleaseId $auditInformation.ReleaseId `
-ReleaseName $auditInformation.ReleaseName `
-ReleaseRequestedFor $auditInformation.ReleaseRequestedFor `
-TenantId @("",$subscriptionInformation.TenantId)[$null -ne $subscriptionInformation] `
-SubscriptionId @("", $subscriptionInformation.SubscriptionId)[$null -ne $subscriptionInformation] `
-ArchetypeInstance $archetypeInstanceJson `
-ArchetypeInstanceName $ArchetypeInstanceName `
-Validate:$($Validate.IsPresent);
Write-Debug "Audit trail created, Id: $auditId";
# Let's get the information if is a subscription
# level deployment or resource group level deployment
$isSubscriptionDeployment = `
$moduleConfigurationDeploymentInformation.IsSubscriptionDeployment;
Add-ItemToCache `
-Key $auditCacheKey `
-Value $auditId `
-Validate:$($Validate.IsPresent);
Write-Debug "Audit Id succesfully cached.";
}
Write-Debug "Deployment template contents is: $moduleConfigurationDeploymentTemplate";
# Runs a custom script only if Script property is present and
        # we are not in Validation mode
        if($null -ne $ModuleConfiguration.Script `
            -and `
           $null -ne $ModuleConfiguration.Script.Command) {
 
            # Orchestrate the deployment of Custom Scripts
            $result = `
                New-CustomScripts `
                    -ModuleConfiguration $moduleConfiguration `
                    -ArchetypeInstanceJson $archetypeInstanceJson `
-Validate:$($Validate.IsPresent);
 
            # Retrieve the results from the script deployment
            $resourceState = $result[0];
 
            # Did the ArchetypeInstanceJson change?
            if($null -ne $result[1]) {
                # Set the ArchetypeInstanceJson only if it is
                # modified by the custom script deployment
                $archetypeInstanceJson = $result[1];
 
                # Re-cache the ArchetypeInstanceJson
                Add-ItemToCache `
                    -Key $ArchetypeInstanceName `
                    -Value $archetypeInstanceJson `
-Validate:$($Validate.IsPresent);
            }     
}
else {
# If a module deployment template exists,
# let's get the deployment parameters.
$moduleConfigurationDeploymentParameters = `
Get-DeploymentParametersFileContents `
# Let's get the module's template information first,
# this template will dictate if is a resource group or
# subscription deployment based on the template's schema
$moduleConfigurationDeploymentInformation = `
Get-DeploymentTemplateFileContents `
-DeploymentConfiguration $moduleConfiguration.Deployment `
-ModuleConfigurationsPath $archetypeInstanceJson.Orchestration.ModuleConfigurationsPath `
-WorkingDirectory $defaultWorkingDirectory;
}
else {
throw "No Resource Manager template found under Deployment.";
}
Write-Debug "Is a subscription deployment: $isSubscriptionDeployment";
$moduleConfigurationDeploymentParameters = $null;
$isSubscriptionDeployment = $false;
$moduleConfigurationResourceGroupName = "";
if($null -ne $moduleConfigurationDeploymentInformation) {
$moduleConfigurationDeploymentTemplate = `
$moduleConfigurationDeploymentInformation.Template;
# Let's get the information if is a subscription
# level deployment or resource group level deployment
$isSubscriptionDeployment = `
$moduleConfigurationDeploymentInformation.IsSubscriptionDeployment;
# If we are not in a subscription deployment
# proceed to create a resource group
if ($null -ne $subscriptionInformation -and `
-not $isSubscriptionDeployment) {
$moduleConfigurationResourceGroupName = `
Get-ResourceGroupName `
-ArchetypeInstanceName $ArchetypeInstanceName `
-ModuleConfiguration $moduleConfiguration;
Write-Debug "Resource Group is: $moduleConfigurationResourceGroupName";
New-ResourceGroup `
-ResourceGroupName $moduleConfigurationResourceGroupName `
-ResourceGroupLocation $subscriptionInformation.Location `
-Validate:$($Validate.IsPresent);
Write-Debug "Resource Group successfully created";
}
Write-Debug "Deployment template contents is: $moduleConfigurationDeploymentTemplate";
# Now continue deploying Policies, RBAC and finally
# the module template
$moduleConfigurationPolicyDeploymentTemplate = `
Get-PolicyDeploymentTemplateFileContents `
-DeploymentConfiguration $moduleConfiguration.Policies `
-ModuleConfigurationsPath $archetypeInstanceJson.Orchestration.ModuleConfigurationsPath `
-WorkingDirectory $defaultWorkingDirectory;
Write-Debug "Policy Deployment template contents is: $moduleConfigurationPolicyDeploymentTemplate";
# If a module deployment template exists,
# let's get the deployment parameters.
$moduleConfigurationDeploymentParameters = `
Get-DeploymentParametersFileContents `
-DeploymentConfiguration $moduleConfiguration.Deployment `
-ModuleConfigurationsPath $archetypeInstanceJson.Orchestration.ModuleConfigurationsPath `
-WorkingDirectory $defaultWorkingDirectory;
}
else {
throw "No Resource Manager template found under Deployment.";
}
$moduleConfigurationPolicyDeploymentParameters = `
Get-PolicyDeploymentParametersFileContents `
-DeploymentConfiguration $moduleConfiguration.Policies `
-ModuleConfigurationsPath $archetypeInstanceJson.Orchestration.ModuleConfigurationsPath `
-WorkingDirectory $defaultWorkingDirectory;
Write-Debug "Policy Deployment parameters contents is: $moduleConfigurationPolicyDeploymentParameters";
Write-Debug "Is a subscription deployment: $isSubscriptionDeployment";
$policyResourceState = @{};
$moduleConfigurationResourceGroupName = "";
if ($null -ne $moduleConfigurationPolicyDeploymentTemplate) {
# If we are not in a subscription deployment
# proceed to create a resource group
if ($null -ne $subscriptionInformation -and `
-not $isSubscriptionDeployment) {
$moduleConfigurationResourceGroupName = `
Get-ResourceGroupName `
-ArchetypeInstanceName $ArchetypeInstanceName `
-ModuleConfiguration $moduleConfiguration;
Write-Debug "Resource Group is: $moduleConfigurationResourceGroupName";
New-ResourceGroup `
-ResourceGroupName $moduleConfigurationResourceGroupName `
-ResourceGroupLocation $subscriptionInformation.Location `
-Validate:$($Validate.IsPresent);
Write-Debug "Resource Group successfully created";
}
# Now continue deploying Policies, RBAC and finally
# the module template
$moduleConfigurationPolicyDeploymentTemplate = `
Get-PolicyDeploymentTemplateFileContents `
-DeploymentConfiguration $moduleConfiguration.Policies `
-ModuleConfigurationsPath $archetypeInstanceJson.Orchestration.ModuleConfigurationsPath `
-WorkingDirectory $defaultWorkingDirectory;
Write-Debug "Policy Deployment template contents is: $moduleConfigurationPolicyDeploymentTemplate";
$moduleConfigurationPolicyDeploymentParameters = `
Get-PolicyDeploymentParametersFileContents `
-DeploymentConfiguration $moduleConfiguration.Policies `
-ModuleConfigurationsPath $archetypeInstanceJson.Orchestration.ModuleConfigurationsPath `
-WorkingDirectory $defaultWorkingDirectory;
Write-Debug "Policy Deployment parameters contents is: $moduleConfigurationPolicyDeploymentParameters";
$policyResourceState = @{};
if ($null -ne $moduleConfigurationPolicyDeploymentTemplate) {
Write-Debug "About to trigger a deployment";
$policyResourceState = `
New-AzureResourceManagerDeployment `
-TenantId $subscriptionInformation.TenantId `
-SubscriptionId $subscriptionInformation.SubscriptionId `
-ResourceGroupName $moduleConfigurationResourceGroupName `
-DeploymentTemplate $moduleConfigurationPolicyDeploymentTemplate `
-DeploymentParameters $moduleConfigurationPolicyDeploymentParameters `
-ModuleConfiguration $moduleConfiguration.Policies `
-ArchetypeInstanceName $ArchetypeInstanceName `
-Location $subscriptionInformation.Location `
-Validate:$($Validate.IsPresent);
Write-Debug "Deployment complete, Resource state is: $(ConvertTo-Json -Compress $policyResourceState)";
}
else {
Write-Debug "No Policy deployment";
}
$moduleConfigurationRBACDeploymentTemplate = `
Get-RbacDeploymentTemplateFileContents `
-DeploymentConfiguration $moduleConfiguration.RBAC `
-ModuleConfigurationsPath $archetypeInstanceJson.Orchestration.ModuleConfigurationsPath `
-WorkingDirectory $defaultWorkingDirectory;
Write-Debug "RBAC Deployment template contents is: $moduleConfigurationRBACDeploymentTemplate";
$moduleConfigurationRBACDeploymentParameters = `
Get-RbacDeploymentParametersFileContents `
-DeploymentConfiguration $moduleConfiguration.RBAC `
-ModuleConfigurationsPath $archetypeInstanceJson.Orchestration.ModuleConfigurationsPath `
-WorkingDirectory $defaultWorkingDirectory;
Write-Debug "RBAC Deployment parameters contents is: $moduleConfigurationRBACDeploymentParameters";
$rbacResourceState = @{};
if ($null -ne $moduleConfigurationRBACDeploymentTemplate) {
Write-Debug "About to trigger a deployment";
$policyResourceState = `
New-AzureResourceManagerDeployment `
-TenantId $subscriptionInformation.TenantId `
-SubscriptionId $subscriptionInformation.SubscriptionId `
-ResourceGroupName $moduleConfigurationResourceGroupName `
-DeploymentTemplate $moduleConfigurationPolicyDeploymentTemplate `
-DeploymentParameters $moduleConfigurationPolicyDeploymentParameters `
-ModuleConfiguration $moduleConfiguration.Policies `
-ArchetypeInstanceName $ArchetypeInstanceName `
-Location $subscriptionInformation.Location `
-Validate:$($Validate.IsPresent);
Write-Debug "Deployment complete, Resource state is: $(ConvertTo-Json -Compress $policyResourceState)";
$rbacResourceState = `
New-AzureResourceManagerDeployment `
-TenantId $subscriptionInformation.TenantId `
-SubscriptionId $subscriptionInformation.SubscriptionId `
-ResourceGroupName $moduleConfigurationResourceGroupName `
-DeploymentTemplate $moduleConfigurationRBACDeploymentTemplate `
-DeploymentParameters $moduleConfigurationRBACDeploymentParameters `
-ModuleConfiguration $moduleConfiguration.RBAC `
-ArchetypeInstanceName $ArchetypeInstanceName `
-Location $subscriptionInformation.Location `
-Validate:$($Validate.IsPresent);
Write-Debug "Deployment complete, Resource state is: $(ConvertTo-Json -Compress $rbacResourceState)";
}
else {
Write-Debug "No RBAC deployment";
}
# This deployment runs last because it could be
# a Subscription or Resource Group level deployment
if ($null -ne $moduleConfigurationDeploymentTemplate) {
Write-Debug "About to trigger a deployment";
$resourceState = `
New-AzureResourceManagerDeployment `
-TenantId $subscriptionInformation.TenantId `
-SubscriptionId $subscriptionInformation.SubscriptionId `
-ResourceGroupName $moduleConfigurationResourceGroupName `
-DeploymentTemplate $moduleConfigurationDeploymentTemplate `
-DeploymentParameters $moduleConfigurationDeploymentParameters `
-ModuleConfiguration $moduleConfiguration.Deployment `
-ArchetypeInstanceName $ArchetypeInstanceName `
-Location $subscriptionInformation.Location `
-Validate:$($Validate.IsPresent);
Write-Debug "Deployment complete, Resource state is: $(ConvertTo-Json -Compress $resourceState)";
}
}
else {
Write-Debug "No Policy deployment";
# If there are deployment outputs, cache the values
if ($null -ne $resourceState.DeploymentOutputs) {
Add-OutputsToCache `
-ModuleConfigurationName $moduleConfigurationName `
-Outputs $resourceState.DeploymentOutputs `
-Validate:$($Validate.IsPresent);
}
$moduleConfigurationRBACDeploymentTemplate = `
Get-RbacDeploymentTemplateFileContents `
-DeploymentConfiguration $moduleConfiguration.RBAC `
-ModuleConfigurationsPath $archetypeInstanceJson.Orchestration.ModuleConfigurationsPath `
-WorkingDirectory $defaultWorkingDirectory;
Write-Debug "RBAC Deployment template contents is: $moduleConfigurationRBACDeploymentTemplate";
$moduleConfigurationRBACDeploymentParameters = `
Get-RbacDeploymentParametersFileContents `
-DeploymentConfiguration $moduleConfiguration.RBAC `
-ModuleConfigurationsPath $archetypeInstanceJson.Orchestration.ModuleConfigurationsPath `
-WorkingDirectory $defaultWorkingDirectory;
Write-Debug "RBAC Deployment parameters contents is: $moduleConfigurationRBACDeploymentParameters";
$rbacResourceState = @{};
if ($null -ne $moduleConfigurationRBACDeploymentTemplate) {
Write-Debug "About to trigger a deployment";
$rbacResourceState = `
New-AzureResourceManagerDeployment `
-TenantId $subscriptionInformation.TenantId `
-SubscriptionId $subscriptionInformation.SubscriptionId `
-ResourceGroupName $moduleConfigurationResourceGroupName `
-DeploymentTemplate $moduleConfigurationRBACDeploymentTemplate `
-DeploymentParameters $moduleConfigurationRBACDeploymentParameters `
-ModuleConfiguration $moduleConfiguration.RBAC `
-ArchetypeInstanceName $ArchetypeInstanceName `
-Location $subscriptionInformation.Location `
-Validate:$($Validate.IsPresent);
Write-Debug "Deployment complete, Resource state is: $(ConvertTo-Json -Compress $rbacResourceState)";
}
else {
Write-Debug "No RBAC deployment";
}
# This deployment runs last because it could be
# a Subscription or Resource Group level deployment
if ($null -ne $moduleConfigurationDeploymentTemplate) {
Write-Debug "About to trigger a deployment";
$resourceState = `
New-AzureResourceManagerDeployment `
-TenantId $subscriptionInformation.TenantId `
-SubscriptionId $subscriptionInformation.SubscriptionId `
-ResourceGroupName $moduleConfigurationResourceGroupName `
-DeploymentTemplate $moduleConfigurationDeploymentTemplate `
-DeploymentParameters $moduleConfigurationDeploymentParameters `
-ModuleConfiguration $moduleConfiguration.Deployment `
-ArchetypeInstanceName $ArchetypeInstanceName `
-Location $subscriptionInformation.Location `
-Validate:$($Validate.IsPresent);
Write-Debug "Deployment complete, Resource state is: $(ConvertTo-Json -Compress $resourceState)";
}
# Store deployment state information
$moduleStateId = `
New-DeploymentStateInformation `
-AuditId $auditId `
-DeploymentId $resourceState.DeploymentId `
-DeploymentName $resourceState.DeploymentName `
-ArchetypeInstanceName $ArchetypeInstanceName `
-ModuleConfigurationName $moduleConfigurationName `
-ResourceStates $resourceState.ResourceStates `
-ResourceIds $resourceState.ResourceIds `
-ResourceGroupName $resourceState.ResourceGroupName `
-DeploymentTemplate $resourceState.DeploymentTemplate `
-DeploymentParameters $resourceState.DeploymentParameters `
-DeploymentOutputs $resourceState.DeploymentOutputs `
-TenantId @("", $subscriptionInformation.TenantId)[$null -ne $subscriptionInformation] `
-SubscriptionId @("", $subscriptionInformation.SubscriptionId)[$null -ne $subscriptionInformation] `
-Policies $policyResourceState `
-RBAC $rbacResourceState `
-Validate:$($Validate.IsPresent);
Write-Debug "Module state created, Id: $($moduleStateId)";
}
# If there are deployment outputs, cache the values
if ($null -ne $resourceState.DeploymentOutputs) {
Add-OutputsToCache `
-ModuleConfigurationName $moduleConfigurationName `
-Outputs $resourceState.DeploymentOutputs `
-Validate:$($Validate.IsPresent);
}
# Store deployment state information
$moduleStateId = `
New-DeploymentStateInformation `
-AuditId $auditId `
-DeploymentId $resourceState.DeploymentId `
-DeploymentName $resourceState.DeploymentName `
-ArchetypeInstanceName $ArchetypeInstanceName `
-ModuleConfigurationName $moduleConfigurationName `
-ResourceStates $resourceState.ResourceStates `
-ResourceIds $resourceState.ResourceIds `
-ResourceGroupName $resourceState.ResourceGroupName `
-DeploymentTemplate $resourceState.DeploymentTemplate `
-DeploymentParameters $resourceState.DeploymentParameters `
-DeploymentOutputs $resourceState.DeploymentOutputs `
-TenantId @("", $subscriptionInformation.TenantId)[$null -ne $subscriptionInformation] `
-SubscriptionId @("", $subscriptionInformation.SubscriptionId)[$null -ne $subscriptionInformation] `
-Policies $policyResourceState `
-RBAC $rbacResourceState `
-Validate:$($Validate.IsPresent);
Write-Debug "Module state created, Id: $($moduleStateId)";
}
catch {
Write-Host "An error ocurred while running New-Deployment";
$errorMessage = `
$(Get-Exception -ErrorObject $_);
Write-Host $errorMessage;
throw $errorMessage;
Write-Error $errorMessage;
}
}
@ -986,8 +1014,8 @@ Function Get-SubscriptionInformation {
$subscriptionNameMatch = `
$ArchetypeInstanceJson.$archetypeInstanceSubscriptions.Keys `
-match $SubscriptionName;
if($archetypeInstanceSubscriptions `
-and $subscriptionNameMatch) {
if($null -ne $archetypeInstanceSubscriptions `
-and $null -ne $subscriptionNameMatch) {
# Retrieve case-sensitive key name from case-insensitive key name using match operation
$SubscriptionName = $subscriptionNameMatch[0];
$subscriptionInformation = `

Просмотреть файл

@ -0,0 +1,156 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using VDC.Core.Models;
namespace VDC.Core
{
public class DirectedGraph
{
public List<Vertex> Vertices { get; } = new List<Vertex>();
public List<Vertex> TopologicalSort { get; private set; } = new List<Vertex>();
private LinkedList<Vertex> _TopologicalSort { get; } = new LinkedList<Vertex>();
int Time { get; set; }
public int GraphSize
{
get
{
return Vertices.Count;
}
}
public void Generate(string jsonGraph)
{
try
{
var moduleConfigurations =
JsonConvert.DeserializeObject<List<GraphModel>>(
jsonGraph);
foreach (var moduleConfiguration in moduleConfigurations.Where(m => m.Enabled))
{
// Add to vertices list
var vertex = new Vertex(moduleConfiguration.Name)
{
Color = Color.White
};
AddVertex(vertex);
}
foreach (var moduleConfiguration in moduleConfigurations.Where(m => m.Enabled))
{
// Let's analyze the dependencies and add them
// as an edge of the parent vertex
if(moduleConfiguration.DependsOn != null &&
moduleConfiguration.DependsOn.Count > 0)
{
var childVertex =
Vertices
.Where(v => v.Name.Equals(
moduleConfiguration.Name,
StringComparison.InvariantCultureIgnoreCase))
.FirstOrDefault();
foreach (var dependency in moduleConfiguration.DependsOn)
{
// Find the module configuration in the list
// of vertices
var parentVertex =
Vertices
.Where(v => v.Name.Equals(
dependency,
StringComparison.InvariantCultureIgnoreCase))
.FirstOrDefault();
if(parentVertex == null)
{
throw new Exception($"Parent node: {dependency} not found, make sure it exists and doesn't have Enabled: false.");
}
// Let's add edge like follows:
// parentVertex -> to -> childVertex
parentVertex.AddEdge(childVertex);
}
}
}
}
catch
{
throw;
}
}
private void AddVertex(Vertex vertex)
{
try
{
if(!Vertices.Any(v => v.Name.Equals(vertex.Name)))
{
Vertices.Add(vertex);
}
}
catch
{
throw;
}
}
public void DFS()
{
foreach (var vertex in Vertices)
{
if(vertex.Color == Color.White)
{
DFS_Visit(vertex);
}
}
GenerateTopologicalSort();
}
private void GenerateTopologicalSort()
{
// Let's reverse the DFS
TopologicalSort =
_TopologicalSort.OrderByDescending(
i => i.EndTime).ToList();
}
private void DFS_Visit(Vertex vertex)
{
Time++;
vertex.StartTime = Time;
vertex.Color = Color.Gray;
foreach (var edge in vertex.Edges)
{
if (edge.Color == Color.White)
{
DFS_Visit(edge);
}
else if(edge.Color == Color.Gray)
{
throw new Exception($"Circular reference detected on node: {vertex.Name}");
}
}
vertex.Color = Color.Black;
Time++;
vertex.EndTime = Time;
_TopologicalSort.AddFirst(vertex);
}
public void ParallelJobScheduling()
{
var allUnscheduled =
Vertices
.Where(v => !v.IsVisited)
.ToList();
}
private void ScheduleJobs(List<Vertex> vertices)
{
var x = vertices.SelectMany(i => i.Edges).ToList();
}
}
}

Просмотреть файл

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,81 @@
using System.Collections.Generic;
using System.Linq;
using System;
namespace VDC.Core.Models
{
public class GraphModel
{
public string Name { get; set; }
public bool Enabled { get; set; } = true;
public List<string> DependsOn { get; set; }
}
public class Vertex
{
public Vertex(string name)
{
Name = name;
}
public Vertex(string name, bool isVisited)
{
this.Name = name;
this.IsVisited = isVisited;
}
public string Name { get; set; }
public LinkedList<Vertex> Edges { get; set; } = new LinkedList<Vertex>();
public bool IsVisited { get; set; }
public Color Color { get; set; }
public int StartTime { get; set; }
public int EndTime { get; set; }
public int EdgeCount
{
get
{
return Edges.Count;
}
}
public void AddEdge(Vertex to)
{
if (!Edges.Any(
t => t.Name.Equals(
to.Name,
StringComparison.InvariantCultureIgnoreCase)))
{
Edges.AddLast(to);
}
}
public void AddEdges(IEnumerable<Vertex> to)
{
var uniqueVertices =
Edges.Except(to, new VertexComparer());
Edges.ToList().AddRange(uniqueVertices);
}
}
class VertexComparer : EqualityComparer<Vertex>
{
public override bool Equals(Vertex x, Vertex y)
{
return x.Name.Equals(
y.Name,
StringComparison.InvariantCultureIgnoreCase);
}
public override int GetHashCode(Vertex obj)
{
return obj.Name.GetHashCode();
}
}
public enum Color
{
None = 0,
White = 1,
Gray = 2,
Black = 3
}
}

Просмотреть файл

@ -290,6 +290,7 @@ Class BlobContainerStateRepository: IStateRepository {
-AsHashTable).$moduleInstanceName;
}
else {
Write-Debug "Blob not found"
# blob was not found
return $null;
}
@ -310,11 +311,12 @@ Class BlobContainerStateRepository: IStateRepository {
hidden [string] BlobExists([string] $container,
[string] $blob) {
Write-Debug "About to retrieve Container: $container and Blob: $blob"
$temporalFileName = [Guid]::NewGuid();
$temporalFilePath = `
Join-Path $this.temporalRootPath "$temporalFileName.json";
Write-Debug "Temporal file path: $temporalFilePath"
try {
$blobFound = Get-AzStorageBlobContent `
-Container $container `
@ -323,13 +325,15 @@ Class BlobContainerStateRepository: IStateRepository {
-Context $this.storageAccountContext `
-ErrorAction SilentlyContinue
if ($blobFound -eq $null) {
if ($null -eq $blobFound) {
Write-Debug "No blob found"
return "";
}
else {
$contentJson = `
Get-Content $temporalFilePath `
-Raw;
Write-Debug "Blob found: $contentJson"
return $contentJson;
}
}

Просмотреть файл

@ -72,8 +72,9 @@ Describe "Custom Script Execution Unit Test Cases" {
It "Should execute a Bash script" {
$scriptPath = Join-Path $rootPath -ChildPath '..' -AdditionalChildPath @("Samples", "scripts", "sample-script.sh");
$bashRootPath = bash -c 'echo $PWD';
$scriptPath = Join-Path $bashRootPath -ChildPath 'Orchestration' -AdditionalChildPath @("Tests", "Samples", "scripts", "sample-script.sh");
$scriptPath = $scriptPath.Replace('\', '/')
$command = $scriptPath;
$arguments = @{

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше