mirror of
https://github.com/Microsoft/sql-server-samples.git
synced 2025-12-08 14:58:54 +00:00
Merge pull request #430 from srdan-bozovic-msft/master
Add sample: Managed Instance - prepare subnet for SQL MI deployment
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
# Prepare subnet for Managed Instance deployment
|
||||
|
||||
Script that validates and prepares virtual network and subnet for Managed Instance creation to comply with [networking requirements](https://docs.microsoft.com/azure/sql-database/sql-database-managed-instance-vnet-configuration#requirements).
|
||||
|
||||
### Contents
|
||||
|
||||
[About this sample](#about-this-sample)<br/>
|
||||
[Before you begin](#before-you-begin)<br/>
|
||||
[Run this sample](#run-this-sample)<br/>
|
||||
[Sample details](#sample-details)<br/>
|
||||
[Disclaimers](#disclaimers)<br/>
|
||||
[Related links](#related-links)<br/>
|
||||
|
||||
|
||||
<a name=about-this-sample></a>
|
||||
|
||||
## About this sample
|
||||
|
||||
- **Applies to:** Azure SQL Database
|
||||
- **Key features:** Managed Instance
|
||||
- **Workload:** n/a
|
||||
- **Programming Language:** PowerShell
|
||||
- **Authors:** Srdan Bozovic
|
||||
- **Update history:** n/a
|
||||
|
||||
<a name=before-you-begin></a>
|
||||
|
||||
## Before you begin
|
||||
|
||||
To run this sample, you need the following prerequisites.
|
||||
|
||||
**Software prerequisites:**
|
||||
|
||||
1. PowerShell 5.1
|
||||
2. Azure PowerShell 5.4.2 or higher
|
||||
|
||||
**Azure prerequisites:**
|
||||
|
||||
1. Permission to manage Azure virtual network
|
||||
|
||||
<a name=run-this-sample></a>
|
||||
|
||||
## Run this sample
|
||||
|
||||
Run the script below from either Windows or Azure Cloud Shell
|
||||
|
||||
```powershell
|
||||
|
||||
$scriptUrlBase = 'https://raw.githubusercontent.com/Microsoft/sql-server-samples/master/samples/manage/azure-sql-db-managed-instance/prepare-subnet'
|
||||
|
||||
$parameters = @{
|
||||
subscriptionId = '<subscriptionId>'
|
||||
resourceGroupName = '<resourceGroupName>'
|
||||
virtualNetworkName = '<virtualNetworkName>'
|
||||
subnetName = '<subnetName>'
|
||||
}
|
||||
|
||||
Invoke-Command -ScriptBlock ([Scriptblock]::Create((New-Object System.Net.WebClient).DownloadString($scriptUrlBase+'/prepareSubnet.ps1?t='+ [DateTime]::Now.Ticks))) -ArgumentList $parameters
|
||||
|
||||
```
|
||||
|
||||
<a name=sample-details></a>
|
||||
|
||||
## Sample details
|
||||
|
||||
This sample shows how to prepare Azure virtual network and subnet for Managed Instance deployment using PowerShell
|
||||
|
||||
This is done in three simple steps:
|
||||
- Validate - Selected virtual netwok and subnet are validated for Managed Instance networking requirements
|
||||
- Confirm - User is shown a set of changes that need to be made to prepare subnet for Managed Instance deployment and asked for consent
|
||||
- Prepare - Virtual network and subnet are configured properly
|
||||
|
||||
<a name=disclaimers></a>
|
||||
|
||||
## Disclaimers
|
||||
The scripts and this guide are copyright Microsoft Corporations and are provided as samples. They are not part of any Azure service and are not covered by any SLA or other Azure-related agreements. They are provided as-is with no warranties express or implied. Microsoft takes no responsibility for the use of the scripts or the accuracy of this document. Familiarize yourself with the scripts before using them.
|
||||
|
||||
<a name=related-links></a>
|
||||
|
||||
## Related Links
|
||||
<!-- Links to more articles. Remember to delete "en-us" from the link path. -->
|
||||
|
||||
For more information, see these articles:
|
||||
|
||||
- [What is a Managed Instance (preview)?](https://docs.microsoft.com/azure/sql-database/sql-database-managed-instance)
|
||||
- [Configure a VNet for Azure SQL Database Managed Instance](https://docs.microsoft.com/azure/sql-database/sql-database-managed-instance-vnet-configuration)
|
||||
@@ -0,0 +1,413 @@
|
||||
$parameters = $args[0]
|
||||
|
||||
$subscriptionId = $parameters['subscriptionId']
|
||||
$resourceGroupName = $parameters['resourceGroupName']
|
||||
$virtualNetworkName = $parameters['virtualNetworkName']
|
||||
$subnetName = $parameters['subnetName']
|
||||
$force = $parameters['force']
|
||||
|
||||
function Ensure-Login ()
|
||||
{
|
||||
$context = Get-AzureRmContext
|
||||
If($context.Subscription -eq $null)
|
||||
{
|
||||
Write-Host "Loging in ..."
|
||||
Try
|
||||
{
|
||||
Login-AzureRmAccount -ErrorAction Stop | Out-null
|
||||
}
|
||||
Catch
|
||||
{
|
||||
Write-Host "Login failed: $_" -ForegroundColor Red
|
||||
Exit
|
||||
}
|
||||
|
||||
}
|
||||
Write-Host "User logedin." -ForegroundColor Green
|
||||
}
|
||||
|
||||
function Select-SubscriptionId {
|
||||
param (
|
||||
$subscriptionId
|
||||
)
|
||||
Write-Host "Selecting subscription '$subscriptionId'."
|
||||
$context = Get-AzureRmContext
|
||||
If($context.Subscription.Id -ne $subscriptionId)
|
||||
{
|
||||
Try
|
||||
{
|
||||
Select-AzureRmSubscription -SubscriptionId $subscriptionId -ErrorAction Stop | Out-null
|
||||
}
|
||||
Catch
|
||||
{
|
||||
Write-Host "Subscription selection failed: $_" -ForegroundColor Red
|
||||
Exit
|
||||
}
|
||||
}
|
||||
Write-Host "Subscription selected." -ForegroundColor Green
|
||||
}
|
||||
|
||||
function Load-VirtualNetwork {
|
||||
param (
|
||||
$resourceGroupName,
|
||||
$virtualNetworkName
|
||||
)
|
||||
Write-Host("Loading virtual network '{0}' in resource group '{1}'." -f $virtualNetworkName, $resourceGroupName)
|
||||
$virtualNetwork = Get-AzureRmVirtualNetwork -ResourceGroupName $resourceGroupName -Name $virtualNetworkName -ErrorAction SilentlyContinue
|
||||
If($virtualNetwork.Id -ne $null)
|
||||
{
|
||||
Write-Host "Virtual network loaded." -ForegroundColor Green
|
||||
return $virtualNetwork
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host "Virtual network not found." -ForegroundColor Red
|
||||
Exit
|
||||
}
|
||||
}
|
||||
|
||||
function Load-VirtualNetworkSubnet {
|
||||
param (
|
||||
$virtualNetwork,
|
||||
$subnetName
|
||||
)
|
||||
Write-Host("Loading subnet '{0}'." -f $subnetName)
|
||||
$subnets = $virtualNetwork.Subnets.Name
|
||||
If($true -eq $subnets.Contains($subnetName))
|
||||
{
|
||||
$subnetIndex = $subnets.IndexOf($subnetName)
|
||||
$subnet = $virtualNetwork.Subnets[$subnetIndex]
|
||||
Write-Host "Subnet loaded." -ForegroundColor Green
|
||||
return $subnet
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host "Subnet not found." -ForegroundColor Red
|
||||
Exit
|
||||
}
|
||||
}
|
||||
|
||||
function Verify-Subnet {
|
||||
param (
|
||||
$subnet
|
||||
)
|
||||
Write-Host("Verifying subnet '{0}'." -f $subnet.Name)
|
||||
If($subnet.AddressPrefix.Split('/')[1] -le 28)
|
||||
{
|
||||
Write-Host "Passed Validation - Subnet is of enough size." -ForegroundColor Green
|
||||
}
|
||||
Else
|
||||
{
|
||||
Write-Host "Failed Validation - Minimum supported subnet size is /28." -ForegroundColor Red
|
||||
Exit
|
||||
}
|
||||
If(
|
||||
($subnet.IpConfigurations.Count -eq 0) -and
|
||||
(
|
||||
($subnet.ResourceNavigationLinks.Count -eq 0) -or
|
||||
($subnet.ResourceNavigationLinks[0].LinkedResourceType -eq 'Microsoft.Sql/virtualClusters')
|
||||
)
|
||||
)
|
||||
{
|
||||
Write-Host "Passed Validation - There are no conflicting resources inside the subnet." -ForegroundColor Green
|
||||
}
|
||||
Else
|
||||
{
|
||||
Write-Host "Failed Validation - Subnet is already in use." -ForegroundColor Red
|
||||
Exit
|
||||
}
|
||||
}
|
||||
|
||||
function Verify-DNSServersList {
|
||||
param (
|
||||
$virtualNetwork
|
||||
)
|
||||
Write-Host("Verifying DNS servers list for virtual network '{0}'." -f $virtualNetwork.Name)
|
||||
If(
|
||||
$virtualNetwork.DhcpOptions.DnsServers.Count -eq 0 -or
|
||||
$virtualNetwork.DhcpOptions.DnsServers.Contains('168.63.129.16')
|
||||
)
|
||||
{
|
||||
Write-Host "Passed Validation - DNS Servers List." -ForegroundColor Green
|
||||
return $true
|
||||
}
|
||||
Else
|
||||
{
|
||||
Write-Host "Warning - DNS servers list should contain 168.63.129.16." -ForegroundColor Yellow
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Verify-ServiceEndpoints {
|
||||
param (
|
||||
$subnet
|
||||
)
|
||||
Write-Host("Verifying Service endpoints for subnet '{0}'." -f $subnet.Name)
|
||||
If(
|
||||
$subnet.ServiceEndpoints.Count -eq 0
|
||||
)
|
||||
{
|
||||
Write-Host "Passed Validation - No service endpoints." -ForegroundColor Green
|
||||
return $true
|
||||
}
|
||||
Else
|
||||
{
|
||||
Write-Host "Warning - Service endpoints are not supported." -ForegroundColor Yellow
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function Verify-NSG {
|
||||
param (
|
||||
$subnet
|
||||
)
|
||||
Write-Host("Verifying NSG for subnet '{0}'."-f $subnet.Name)
|
||||
If(
|
||||
$subnet.NetworkSecurityGroup -eq $null
|
||||
)
|
||||
{
|
||||
Write-Host "Passed Validation - No NSG." -ForegroundColor Green
|
||||
return $true
|
||||
}
|
||||
Else
|
||||
{
|
||||
Write-Host "Warning - NSG is not supported before provisioning." -ForegroundColor Yellow
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Load-RouteTable {
|
||||
param (
|
||||
$subnet
|
||||
)
|
||||
Write-Host("Loading Route table for subnet '{0}'." -f $subnet.Name)
|
||||
If(
|
||||
$subnet.RouteTable -ne $null
|
||||
)
|
||||
{
|
||||
$rtSegments = ($subnet.RouteTable.Id).Split("/", [System.StringSplitOptions]::RemoveEmptyEntries)
|
||||
$rtName = $rtSegments[-1].Trim()
|
||||
$rtResourceGroup = $rtSegments[3].Trim()
|
||||
$routeTable = Get-AzureRmRouteTable -ResourceGroupName $rtResourceGroup -Name $rtName
|
||||
Write-Host "Route table loaded." -ForegroundColor Green
|
||||
return $routeTable
|
||||
}
|
||||
Else
|
||||
{
|
||||
Write-Host "Warning - There is no route table on the subnet." -ForegroundColor Yellow
|
||||
return $null
|
||||
}
|
||||
}
|
||||
|
||||
function Verify-RouteTable {
|
||||
param (
|
||||
$subnetAddressPrefix,
|
||||
$routeTable
|
||||
)
|
||||
Write-Host("Verifying Route table '{0}'." -f $routeTable.Name)
|
||||
|
||||
$hasDefaultRule = $false
|
||||
$hasAnyOtherRule = $false
|
||||
|
||||
ForEach($route in $routeTable.Routes)
|
||||
{
|
||||
If(
|
||||
$route.AddressPrefix -eq "0.0.0.0/0" -and `
|
||||
$route.NextHopType -eq "Internet"
|
||||
)
|
||||
{
|
||||
$hasDefaultRule = $true;
|
||||
}
|
||||
Else
|
||||
{
|
||||
$hasAnyOtherRule = $true
|
||||
}
|
||||
}
|
||||
|
||||
If($hasDefaultRule -ne $true)
|
||||
{
|
||||
Write-Host "Warning - 0.0.0.0/0 next hop type Internet rule is missing." -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
If($hasAnyOtherRule -eq $true)
|
||||
{
|
||||
Write-Host "Warning - Route table has rule other then 0.0.0.0/0 next hop type Internet." -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
$isValid = $hasDefaultRule -and ($hasAnyOtherRule -ne $true)
|
||||
|
||||
If(
|
||||
$isValid
|
||||
)
|
||||
{
|
||||
Write-Host "Passed Validation - Route table." -ForegroundColor Green
|
||||
}
|
||||
return $isValid
|
||||
}
|
||||
|
||||
function Prepare-DNSServerList
|
||||
{
|
||||
param($virtualNetwork)
|
||||
Write-Host "Adding 168.63.129.16 to DNS servers list."
|
||||
$virtualNetwork.DhcpOptions.DnsServers += "168.63.129.16"
|
||||
}
|
||||
|
||||
function Prepare-ServiceEndpoints
|
||||
{
|
||||
param($subnet)
|
||||
Write-Host "Removing service endpoints."
|
||||
$subnet.ServiceEndpoints.Clear()
|
||||
}
|
||||
|
||||
function Prepare-NSG
|
||||
{
|
||||
param($subnet)
|
||||
Write-Host "Dissasociating NSG."
|
||||
$subnet.NetworkSecurityGroup = $null
|
||||
}
|
||||
|
||||
function Prepare-RouteTable
|
||||
{
|
||||
param(
|
||||
$existingRouteTable,
|
||||
$virtualNetwork,
|
||||
$subnet
|
||||
)
|
||||
Write-Host "Creating Route table."
|
||||
$defaultRoute = New-AzureRmRouteConfig -Name "default" -AddressPrefix 0.0.0.0/0 -NextHopType "Internet"
|
||||
$routeTableName = "rtManagedInstance" + (Get-Random -Maximum 1000)
|
||||
$routeTable = $null
|
||||
|
||||
Try
|
||||
{
|
||||
$routeTable = New-AzureRmRouteTable -Name $routeTableName -ResourceGroupName $virtualNetwork.ResourceGroupName -Location $virtualNetwork.Location -Route $defaultRoute
|
||||
}
|
||||
Catch
|
||||
{
|
||||
Write-Host "Failed: $_" -ForegroundColor Red
|
||||
}
|
||||
|
||||
Write-Host "Associating Route table."
|
||||
$subnet.RouteTable = $routeTable
|
||||
}
|
||||
|
||||
function Set-VirtualNetwork
|
||||
{
|
||||
param($virtualNetwork)
|
||||
|
||||
Write-Host "Applying changes to the virtual network."
|
||||
Try
|
||||
{
|
||||
Set-AzureRmVirtualNetwork -VirtualNetwork $virtualNetwork -ErrorAction Stop | Out-Null
|
||||
}
|
||||
Catch
|
||||
{
|
||||
Write-Host "Failed: $_" -ForegroundColor Red
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Ensure-Login
|
||||
Select-SubscriptionId -subscriptionId $subscriptionId
|
||||
|
||||
$virtualNetwork = Load-VirtualNetwork -resourceGroupName $resourceGroupName -virtualNetworkName $virtualNetworkName
|
||||
$subnet = Load-VirtualNetworkSubnet -virtualNetwork $virtualNetwork -subnetName $subnetName
|
||||
|
||||
Write-Host
|
||||
|
||||
Verify-Subnet $subnet
|
||||
$isOkDnsServersList = Verify-DNSServersList $virtualNetwork
|
||||
$isOkServiceEndpoints = Verify-ServiceEndpoints $subnet
|
||||
$isOkNSG = Verify-NSG $subnet
|
||||
$routeTable = Load-RouteTable $subnet
|
||||
$hasRouteTable = $routeTable -ne $null
|
||||
$isOkRouteTable = $false
|
||||
If($hasRouteTable)
|
||||
{
|
||||
$isOkRouteTable = Verify-RouteTable $subnet.AddressPrefix $routeTable
|
||||
}
|
||||
|
||||
$isValid = $isOkDnsServersList -and $isOkServiceEndpoints -and $isOkNSG -and $isOkRouteTable
|
||||
|
||||
If($isValid -ne $true)
|
||||
{
|
||||
Write-Host
|
||||
Write-Host("---------- To prepare the virtual network subnet for Managed Instance this script will: --------------- ") -ForegroundColor Yellow
|
||||
Write-Host
|
||||
If($isOkDnsServersList -ne $true)
|
||||
{
|
||||
Write-Host "[DNS] Add IP address 168.63.129.16 at the end of DNS servers list." -ForegroundColor Yellow
|
||||
}
|
||||
If($isOkServiceEndpoints -ne $true)
|
||||
{
|
||||
Write-Host "[Endpoints] Remove all service endpoints." -ForegroundColor Yellow
|
||||
}
|
||||
If($isOkNSG -ne $true)
|
||||
{
|
||||
Write-Host "[NSG] Disassociate NSG from the subnet." -ForegroundColor Yellow
|
||||
}
|
||||
If($isOkRouteTable -ne $true)
|
||||
{
|
||||
If($hasRouteTable)
|
||||
{
|
||||
Write-Host "[UDR] Disassociate existing Route table from the subnet." -ForegroundColor Yellow
|
||||
}
|
||||
Write-Host "[UDR] Create Route table with single 0.0.0.0/0 -> Internet rule and associate it to the subnet." -ForegroundColor Yellow
|
||||
}
|
||||
Write-Host
|
||||
Write-Host("-------------------------------------------------------------------------------------------------------- ") -ForegroundColor Yellow
|
||||
Write-Host
|
||||
|
||||
|
||||
$applyChanges = $force
|
||||
|
||||
If($applyChanges -ne $true)
|
||||
{
|
||||
$reply = Read-Host -Prompt "Do you want to make these changes? [y/n]"
|
||||
$applyChanges = $reply -match "[yY]"
|
||||
Write-Host
|
||||
}
|
||||
|
||||
If ($applyChanges)
|
||||
{
|
||||
If($isOkDnsServersList -ne $true)
|
||||
{
|
||||
Prepare-DNSServerList $virtualNetwork
|
||||
}
|
||||
|
||||
If($isOkServiceEndpoints -ne $true)
|
||||
{
|
||||
Prepare-ServiceEndpoints $subnet
|
||||
}
|
||||
|
||||
If($isOkNSG -ne $true)
|
||||
{
|
||||
Prepare-NSG $subnet
|
||||
}
|
||||
|
||||
If($isOkRouteTable -ne $true)
|
||||
{
|
||||
Prepare-RouteTable $routeTable $virtualNetwork $subnet
|
||||
}
|
||||
|
||||
Set-VirtualNetwork $virtualNetwork
|
||||
|
||||
Write-Host
|
||||
Write-Host "Subnet prepared for the Managed Instance." -ForegroundColor Green
|
||||
Write-Host "https://portal.azure.com/#create/Microsoft.SQLManagedInstance"
|
||||
}
|
||||
Else
|
||||
{
|
||||
Write-Host
|
||||
Write-Host "Subnet preparation canceled." -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
}
|
||||
Else
|
||||
{
|
||||
Write-Host
|
||||
Write-Host "Subnet is already prepared." -ForegroundColor Green
|
||||
Write-Host "https://portal.azure.com/#create/Microsoft.SQLManagedInstance"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user