Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ parameters:
- name: removeDeployment
displayName: Remove deployed module
type: boolean
default: false # Only one Network Watcher can exist in the same location. If removed, a default would be created in a dedicated RG
default: true
- name: prerelease
displayName: Publish prerelease module
type: boolean
Expand Down
5 changes: 2 additions & 3 deletions .github/workflows/ms.network.networkwatchers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
type: boolean
description: 'Remove deployed module'
required: false
default: false # Only one Network Watcher can exist in the same location. If removed, a default would be created in a dedicated RG
default: true
prerelease:
type: boolean
description: 'Publish prerelease module'
Expand Down Expand Up @@ -106,8 +106,7 @@ jobs:
- name: 'Using test file [${{ matrix.moduleTestFilePaths }}]'
uses: ./.github/actions/templates/validateModuleDeployment
with:
templateFilePath: '${{ env.modulePath }}/deploy.bicep'
parameterFilePath: '${{ env.modulePath }}/${{ matrix.moduleTestFilePaths }}'
templateFilePath: '${{ env.modulePath }}/${{ matrix.moduleTestFilePaths }}'
location: '${{ env.location }}'
resourceGroupName: '${{ env.resourceGroupName }}'
subscriptionId: '${{ secrets.ARM_SUBSCRIPTION_ID }}'
Expand Down
4 changes: 3 additions & 1 deletion docs/wiki/The CI environment - Deployment validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ The removal process will delete all resources created by the deployment. The lis

1. Recursively fetching the list of resource IDs created in the deployment (identified via the deployment name used).
1. Ordering the list based on resource IDs segment count (ensures child resources are removed first. E.g., `storageAccount/blobServices` comes before `storageAccount` as it has one more segments delimited by `/`).
1. Filtering out resources used as dependencies for different modules from the list (e.g., the commonly used Log Analytics workspace).
1. Filtering out resources must remain even after the test concluded from the list. This contains, but is not limited to:
1. Resources that are autogenerated by Azure and can cause issues if not controlled (e.g., the Network Watcher resource group that is autogenerated and shared by multiple module tests)
1. Dependencies for different modules (e.g., the commonly used Log Analytics workspace).
1. Moving specific resource types to the top of the list (if a certain order is required). For example, `diagnosticSettings` need to be removed before the resource to which they are applied, even though they are no child-resources.

After a resource is removed (this happens after each resource in the list), if defined, the script will perform a **post removal operation**. This can be used for those resource types that require post-processing, like purging a soft-deleted Key Vault.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
@description('Optional. The location to deploy to.')
param location string = resourceGroup().location

@description('Required. The name of the Virtual Network to create.')
param virtualNetworkName string

@description('Required. The name of the Managed Identity to create.')
param managedIdentityName string

@description('Required. The name of the first Network Security Group to create.')
param firstNetworkSecurityGroupName string

@description('Required. The name of the second Network Security Group to create.')
param secondNetworkSecurityGroupName string

@description('Required. The name of the Virtual Machine to create.')
param virtualMachineName string

@description('Optional. The password to leverage for the VM login.')
@secure()
param password string = newGuid()

resource virtualNetwork 'Microsoft.Network/virtualNetworks@2022-01-01' = {
name: virtualNetworkName
location: location
properties: {
addressSpace: {
addressPrefixes: [
'10.0.0.0/24'
]
}
subnets: [
{
name: 'defaultSubnet'
properties: {
addressPrefix: '10.0.0.0/24'
}
}
]
}
}

resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
name: managedIdentityName
location: location
}

resource firstNetworkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2022-05-01' = {
name: firstNetworkSecurityGroupName
location: location
}

resource secondNetworkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2022-05-01' = {
name: secondNetworkSecurityGroupName
location: location
}

resource networkInterface 'Microsoft.Network/networkInterfaces@2022-05-01' = {
name: '${virtualMachineName}-nic'
location: location
properties: {
ipConfigurations: [
{
name: 'ipconfig01'
properties: {
subnet: {
id: virtualNetwork.properties.subnets[0].id
}
}
}
]
}
}

resource virtualMachine 'Microsoft.Compute/virtualMachines@2022-08-01' = {
name: virtualMachineName
location: location
properties: {
networkProfile: {
networkInterfaces: [
{
id: networkInterface.id
properties: {
deleteOption: 'Delete'
primary: true
}
}
]
}
storageProfile: {
imageReference: {
offer: 'UbuntuServer'
publisher: 'Canonical'
sku: '18.04-LTS'
version: 'latest'
}
osDisk: {
deleteOption: 'Delete'
createOption: 'FromImage'
}
}
hardwareProfile: {
vmSize: 'Standard_B1ms'
}
osProfile: {
adminUsername: '${virtualMachineName}cake'
adminPassword: password
computerName: virtualMachineName
linuxConfiguration: {
disablePasswordAuthentication: false
}
}
}
}

resource extension 'Microsoft.Compute/virtualMachines/extensions@2021-07-01' = {
name: 'NetworkWatcherAgent'
parent: virtualMachine
location: location
properties: {
publisher: 'Microsoft.Azure.NetworkWatcher'
type: 'NetworkWatcherAgentLinux'
typeHandlerVersion: '1.4'
autoUpgradeMinorVersion: true
enableAutomaticUpgrade: false
settings: {}
protectedSettings: {}
suppressFailures: false
}
}

@description('The principal ID of the created Managed Identity.')
output managedIdentityPrincipalId string = managedIdentity.properties.principalId

@description('The resource ID of the created Virtual Machine.')
output virtualMachineResourceId string = virtualMachine.id

@description('The resource ID of the first created Network Security Group.')
output firstNetworkSecurityGroupResourceId string = firstNetworkSecurityGroup.id

@description('The resource ID of the second created Network Security Group.')
output secondNetworkSecurityGroupResourceId string = secondNetworkSecurityGroup.id
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
targetScope = 'subscription'

// ========== //
// Parameters //
// ========== //
@description('Optional. The name of the resource group to deploy for testing purposes.')
@maxLength(90)
param resourceGroupName string = 'NetworkWatcherRG' // Note, this is the default NetworkWatcher resource group. Do not change.

@description('Optional. The location to deploy resources to.')
param location string = deployment().location

@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.')
param serviceShort string = 'nnwcom'

// =========== //
// Deployments //
// =========== //

// General resources
// =================
resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = {
name: resourceGroupName
location: location
}

module resourceGroupResources 'dependencies.bicep' = {
scope: resourceGroup
name: '${uniqueString(deployment().name, location)}-paramNested'
params: {
managedIdentityName: 'dep-<<namePrefix>>-msi-${serviceShort}'
firstNetworkSecurityGroupName: 'dep-<<namePrefix>>-nsg-1-${serviceShort}'
secondNetworkSecurityGroupName: 'dep-<<namePrefix>>-nsg-2-${serviceShort}'
virtualMachineName: 'dep-<<namePrefix>>-vm-${serviceShort}'
virtualNetworkName: 'dep-<<namePrefix>>-vnet-${serviceShort}'
location: location
}
}

// Diagnostics
// ===========
module diagnosticDependencies '../../../../.shared/dependencyConstructs/diagnostic.dependencies.bicep' = {
scope: resourceGroup
name: '${uniqueString(deployment().name, location)}-diagnosticDependencies'
params: {
storageAccountName: 'dep<<namePrefix>>diasa${serviceShort}01'
logAnalyticsWorkspaceName: 'dep-<<namePrefix>>-law-${serviceShort}'
eventHubNamespaceEventHubName: 'dep-<<namePrefix>>-evh-${serviceShort}'
eventHubNamespaceName: 'dep-<<namePrefix>>-evhns-${serviceShort}'
location: location
}
}

// ============== //
// Test Execution //
// ============== //
#disable-next-line no-hardcoded-location // Disabled as the default RG & location are created in always one location, but each test has to deploy into a different one
var testLocation = 'westeurope'
module testDeployment '../../deploy.bicep' = {
scope: resourceGroup
name: '${uniqueString(deployment().name)}-test-${serviceShort}'
params: {
name: 'NetworkWatcher_${testLocation}'
location: testLocation
connectionMonitors: [
{
name: '<<namePrefix>>-${serviceShort}-cm-001'
endpoints: [
{
name: '<<namePrefix>>-subnet-001(${resourceGroup.name})'
resourceId: resourceGroupResources.outputs.virtualMachineResourceId
type: 'AzureVM'
}
{
address: 'www.office.com'
name: 'Office Portal'
type: 'ExternalAddress'
}
]
testConfigurations: [
{
httpConfiguration: {
method: 'Get'
port: 80
preferHTTPS: false
requestHeaders: []
validStatusCodeRanges: [
'200'
]
}
name: 'HTTP Test'
protocol: 'Http'
successThreshold: {
checksFailedPercent: 5
roundTripTimeMs: 100
}
testFrequencySec: 30
}
]
testGroups: [
{
destinations: [
'Office Portal'
]
disable: false
name: 'TestHTTPBing'
sources: [
'<<namePrefix>>-subnet-001(${resourceGroup.name})'
]
testConfigurations: [
'HTTP Test'
]
}
]
workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId
}
]
flowLogs: [
{
enabled: false
storageId: diagnosticDependencies.outputs.storageAccountResourceId
targetResourceId: resourceGroupResources.outputs.firstNetworkSecurityGroupResourceId
}
{
formatVersion: 1
name: '<<namePrefix>>-${serviceShort}-fl-001'
retentionInDays: 8
storageId: diagnosticDependencies.outputs.storageAccountResourceId
targetResourceId: resourceGroupResources.outputs.secondNetworkSecurityGroupResourceId
trafficAnalyticsInterval: 10
workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId
}
]
roleAssignments: [
{
roleDefinitionIdOrName: 'Reader'
principalIds: [
resourceGroupResources.outputs.managedIdentityPrincipalId
]
principalType: 'ServicePrincipal'
}
]
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
targetScope = 'subscription'

// ========== //
// Parameters //
// ========== //
@description('Optional. The name of the resource group to deploy for testing purposes.')
@maxLength(90)
param resourceGroupName string = 'NetworkWatcherRG' // Note, this is the default NetworkWatcher resource group. Do not change.

@description('Optional. The location to deploy resources to.')
param location string = deployment().location

@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.')
param serviceShort string = 'nnwmin'

// =========== //
// Deployments //
// =========== //

// General resources
// =================
resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = {
name: resourceGroupName
location: location
}

// ============== //
// Test Execution //
// ============== //
#disable-next-line no-hardcoded-location // Disabled as the default RG & location are created in always one location, but each test has to deploy into a different one
var testLocation = 'northeurope'
module testDeployment '../../deploy.bicep' = {
scope: resourceGroup
name: '${uniqueString(deployment().name)}-test-${serviceShort}'
params: {
// Note: This value is not required and only set to enable testing
location: testLocation
}
}
Loading