VrtuModule.psm1
function New-Deploy { param([string]$Path, [string]$File, [string]$SubscriptionName , [string]$ResourceGroupName , [string]$Location, [string]$Email, [string]$PiraeusDns, [string]$MonitorDns, [string]$VirtualRtuId, [string]$PiraeusClusterName, [string]$VrtuClusterName, [string]$MonitorClusterName, [string]$OrleansStorageAcctName, [string]$VrtuStorageAcctName, [string]$Domain, [int]$Port, [string]$IoTHubName, [string]$AppID, [string]$Password, [string]$LogLevel) $start = Get-Date New-PiraeusDeploy -Path $Path -File $File -SubscriptionName $SubscriptionName -ResourceGroupName $ResourceGroupName -Location $Location -Email $Email -Dns $PiraeusDns -ClusterName $PiraeusClusterName -AppID $AppID -Password $Password -OrleansStorageAcctName $OrleansStorageAcctName -LogLevel $LogLevel #read the config file $config = Get-Content -Raw -Path $File | ConvertFrom-Json $symmetricKey = $config.symmetricKey $hostname = $config.piraeusHostname $appId = $config.appId $pwd = $config.pwd New-VrtuVnetDeploy -Path $Path -File $File -SubscriptionName $SubscriptionName -ResourceGroupName $ResourceGroupName -Location $Location -VirtualRtuId $VirtualRtuId -Hostname $hostname -SymmetricKey $symmetricKey -IoTHubName $IoTHubName -StorageAcctName $VrtuStorageAcctName -ClusterName $VrtuClusterName -AppID $appId -Password $pwd -LogLevel $LogLevel -StartTime $start New-WebMonitorDeploy -Path $Path -File $File -SubscriptionName $SubscriptionName -ResourceGroupName $ResourceGroupName -Location $Location -PiraeusHostname $hostname -VirtualRtuId $VirtualRtuId -StorageAcctName $VrtuStorageAcctName -SymmetricKey $symmetricKey -Dns $MonitorDns -Email $Email -ClusterName $MonitorClusterName -Domain $Domain -Port $Port -AppID $appId -Password $pwd -LogLevel $LogLevel -StartTime $start } function New-PiraeusDeploy { param([string]$Path, [string]$File, [string]$SubscriptionName, [string]$ResourceGroupName, [string]$Location, [string]$Email, [string]$Dns, [string]$ClusterName, [string]$AppID, [string]$Password, [string]$OrleansStorageAcctName, [int]$NodeCount, [string]$GatewayVmSize, [string]$OrleansVmSize, [string]$LogLevel) $env:AZURE_HTTP_USER_AGENT='pid-332e88b9-31d3-5070-af65-de3780ad5c8b' kubectl create namespace "cert-manager" if($GatewayVmSize.Length -eq 0) { $GatewayVmSize = "Standard_D2s_v3" } if($OrleansVmSize.Length -eq 0) { $OrleansVmSize = "Standard_D4s_v3" } if($NodeCount -eq 0) { $NodeCount = 1 } if($LogLevel.Length -eq 0) { $LogLevel = "Information" } if($File.Length -eq 0) { $dateTimeString = Get-Date -Format "MM-dd-yyyyTHH-mm-ss" $File = "./piraeus-" + $dateTimeString + ".json" } $start = Get-Date $step = 1 Update-Step -Step $step -Message "Clean up previous local config from previous Kubectl deployment (optional)" -Start $start $step++ New-KubectlClusterCleanup -ClusterName $ClusterName -ResourceGroupName $ResourceGroupName Update-Step -Step $step -Message "Adding Application Insights extension to Azure CLI" -Start $start $step++ Set-AppInsightsExtension Update-Step -Step $step -Message "Adding Iot Hub extension to Azure CLI" -Start $start Set-IoTHubExtension $step++ Update-Step -Step $step -Message "Set Subscription for deployment" -Start $start $step++ Set-Subscription -SubscriptionName $SubscriptionName Update-Step -Step $step -Message "Set Resource Group for deployment" -Start $start $step++ Set-ResourceGroup -ResourceGroupName $ResourceGroupName -Location $Location Update-Step -Step $step -Message "If exists delete Piraeus AKS cluster $ClusterName from Azure" -Start $start $step++ Remove-AksCluster -ClusterName $ClusterName -ResourceGroupName $ResourceGroupName Update-Step -Step $step -Message "Set Service Principal" -Start $start $step++ $spn = Get-ServicePrincipal -AppID $AppID -Password $Password $spnAppId = $spn."appId" $spnPwd = $spn."pwd" Update-Step -Step $step -Message "Create Orleans storage account" -Start $start $step++ $orleansNameAvailable = Get-StorageAccountNameAvailable -StorageAcctName "$OrleansStorageAcctName" -SubscriptionName "$SubscriptionName" if($orleansNameAvailable) { Write-Host "Storage Account Name available" New-StorageAccount -StorageAcctName $OrleansStorageAcctName -Location $Location -ResourceGroupName $ResourceGroupName } $orleansConnectionString = Get-StorageAccountConnectionString -StorageAcctName $OrleansStorageAcctName -ResourceGroupName $ResourceGroupName if($LASTEXITCODE -ne 0) { Write-Host "Failed to get orleans storage account connection string...terminating script." -ForegroundColor Yellow return } Update-Step -Step $step -Message "Orleans storage account connection string obtained" -Start $start $step++ Update-Step -Step $step -Message "Create Audit storage account" -Start $start $step++ $auditStorageAcctName = $OrleansStorageAcctName + "audit" $auditNameAvailable = Get-StorageAccountNameAvailable -SubscriptionName $SubscriptionName -StorageAcctName $auditStorageAcctName if($auditNameAvailable) { New-StorageAccount -StorageAcctName $auditStorageAcctName -Location $Location -ResourceGroupName $ResourceGroupName } $auditConnectionString = Get-StorageAccountConnectionString -StorageAcctName $auditStorageAcctName -ResourceGroupName $ResourceGroupName if($LASTEXITCODE -ne 0) { Write-Host "Failed to get audit storage account connection string...terminating script." -ForegroundColor Yellow return } Update-Step -Step $step -Message "Audit storage account connection string obtained" -Start $start $step++ Update-Step -Step $step -Message "Creating new Piraeus AKS cluster" -Start $start $step++ Write-Host "Cluster = $ClusterName" -ForegroundColor Cyan New-AksCluster -ClusterName $ClusterName -ResourceGroupName $ResourceGroupName -AppId "$spnAppId" -Password "$spnPwd" -VmSize $GatewayVmSize -NodeCount $NodeCount Update-Step -Step $step -Message "Get AKS credentials" -Start $start $step++ Get-AksCredentials -ClusterName $ClusterName -ResourceGroupName $ResourceGroupName Update-Step -Step $step -Message "Apply HELM RBAC" -Start $start $step++ New-KubectlApply -Filename "$Path/helm-rbac.yaml" -Namespace "kube-system" Update-Step -Step $step -Message "Start Tiller" -Start $start $step++ helm init --service-account tiller Set-Timer -Message "...waiting 45 seconds for Tiller to start" -Seconds 45 Update-Step -Step $step -Message "Set Node pool label for Piraeus front end" -Start $start $step++ Set-NodeLabel -NodeMatchValue "nodepool1" -Key "pool" -Value "nodepool1" Update-Step -Step $step -Message "Add cert manager for Let's Encrypt" -Start $start $step++ Add-CertManager Set-Timer -Message "...waiting 45 seconds for cert-manager to initialize" -Seconds 45 Update-Step -Step $step -Message "Add cert issuer for Lets Encrypt" -Start $start $step++ Add-Issuer -Email $Email -IssuerPath "$Path/issuer.yaml" -IssuerDestination "$Path/issuer-copy.yaml" Set-Timer -Message "...waiting 30 seconds for issuer to initialize" -Seconds 30 Update-Step -Step $step -Message "Upate local HELM repo" -Start $start $step++ helm repo add stable https://kubernetes-charts.storage.googleapis.com/ Update-Step -Step $step -Message "Add NGINX" -Start $start $step++ Add-NGINX Set-Timer "...waiting 45 seconds for nginx to initialize" -Seconds 45 Update-Step -Step $step -Message "Get External IP address" -Start $start $step++ $IP = Get-ExternalIP Update-Step -Step $step -Message "Create Public IP ID" -Start $start $step++ $PUBLICIPID=$(az network public-ip list --query "[?ipAddress!=null]|[?contains(ipAddress, '$IP')].[id]" --output tsv) Update-Step -Step $step -Message "Update Public IP ID" -Start $start $step++ Update-PublicIP -PublicIP $PUBLICIPID -Dns $Dns -SubscriptionName $SubscriptionName Update-Step -Step $step -Message "Set certificate for cert-manager and Lets Encrypt" -Start $start $step++ Set-Certificate -Dns $Dns -Location $Location -Path "$Path/certificate.yaml" -Destination "$Path/certificate-copy.yaml" Update-Step -Step $step -Message "Add Orleans cluster for 2nd node pool" -Start $start $step++ Add-NodePool -ResourceGroupName $ResourceGroupName -ClusterName $ClusterName -NodePoolName "nodepool2" -NodeCount $NodeCount -VmSize $OrleansVmSize Set-Timer -Message "...waiting 60 seconds for node to initialize" -Seconds 60 Update-Step -Step $step -Message "Create node pool label for 2nd node pool" -Start $start $step++ Set-NodeLabel "nodepool2" "pool" "nodepool2" Update-Step -Step $step -Message "Creating random Piraeus Management API keys" -Start $start $step++ $apiKey1 = New-RandomKey -Length 16 $apiKey2 = New-RandomKey -Length 16 $apiSecurityCodes = $apiKey1 + ";" + $apiKey2 $apiIssuer = "http://$Dns.$Location.cloudapp.azure.com/mgmt" $apiAudience = $apiIssuer $identityClaimType = "http://$Dns.$Location.cloudapp.azure.com/name" $issuer = "http://$Dns.$Location.cloudapp.azure.com/" $audience = $issuer $coapAuthority = "http://$Dns.$Location.cloudapp.azure.com" $tokenType = "JWT" Update-Step -Step $step -Message "Creating random Piraeus Management API symmetric key" -Start $start $step++ $apiSymmetricKey = New-RandomKey -Length 32 Update-Step -Step $step -Message "Creating random Piraeus Gateway symmetric key" -Start $start $step++ $symmetricKey = New-RandomKey -Length 32 Update-Step -Step $step -Message "Creating App Insights for Orleans cluster and getting instrumentation key" -Start $start $step++ $siloAIKey = Get-InstrumentationKey "$Dns-silo" -ResourceGroupName $ResourceGroupName -Location $Location Update-Step -Step $step -Message "Install Orleans cluster from helm chart" -Start $start $step++ helm install "$Path/piraeus-silo" --name piraeus-silo --namespace kube-system --set dataConnectionString=$orleansConnectionString --set instrumentationKey=$siloAIKey --set logLevel=$LogLevel if($LASTEXITCODE -ne 0 ) { Update-Step -Step $step -Message "Waiting for Kubernetes API Services to start" -Start $start $step++ Set-WaitForApiServices Update-Step -Step $step -Message "Trying again to install Orleans cluster from helm chart" -Start $start $step++ helm install "$Path/piraeus-silo" --name piraeus-silo --namespace kube-system --set dataConnectionString=$orleansConnectionString --set instrumentationKey=$siloAIKey --set logLevel=$LogLevel } Update-Step -Step $step -Message "Creating App Insights for Piraeus Management API and getting instrumentation key" -Start $start $step++ $mgmtAIKey = Get-InstrumentationKey "$Dns-api" -ResourceGroupName $ResourceGroupName -Location $Location Update-Step -Step $step -Message "Install Piraeus Management API from helm chart" -Start $start $step++ helm install "$Path/piraeus-mgmt-api" --namespace kube-system --set dataConnectionString="$orleansConnectionString" --set managementApiIssuer="$apiIssuer" --set managementApiAudience="$apiAudience" --set managmentApiSymmetricKey="$apiSymmetricKey" --set managementApiSecurityCodes="$apiSecurityCodes" --set instrumentationKey=$mgmtAIKey --set logLevel=$LogLevel if($LASTEXITCODE -ne 0 ) { Update-Step -Step $step -Message "Waiting for Kubernetes API Services to start" -Start $start $step++ Set-WaitForApiServices Update-Step -Step $step -Message "Trying again to install Piraeus Management API from helm chart" -Start $start $step++ helm install "$Path/piraeus-mgmt-api" --namespace kube-system --set dataConnectionString="$orleansConnectionString" --set managementApiIssuer="$apiIssuer" --set managementApiAudience="$apiAudience" --set managmentApiSymmetricKey="$apiSymmetricKey" --set managementApiSecurityCodes="$apiSecurityCodes" --set instrumentationKey=$mgmtAIKey --set logLevel=$LogLevel } Update-Step -Step $step -Message "Creating App Insights for Piraeus Web Socket Gateway and getting instrumentation key" -Start $start $step++ $websocketAIKey = Get-InstrumentationKey "$Dns-websocket" -ResourceGroupName $ResourceGroupName -Location $Location Update-Step -Step $step -Message "Install Piraeus Web Socket Gateway from helm chart" -Start $start $step++ helm install "$Path/piraeus-websocket" --namespace kube-system --set dataConnectionString="$orleansConnectionString" --set auditConnectionString="$auditConnectionString" --set clientIdentityNameClaimType="$identityClaimType" --set clientIssuer="$issuer" --set clientAudience="$audience" --set clientTokenType="$tokenType" --set clientSymmetricKey="$symmetricKey" --set coapAuthority="$coapAuthority" --set instrumentationKey=$websocketAIKey --set logLevel=$LogLevel if($LASTEXITCODE -ne 0 ) { Update-Step -Step $step -Message "Waiting for Kubernetes API Services to start" -Start $start $step++ Set-WaitForApiServices Update-Step -Step $step -Message "Trying again to install Piraeus Web Socket Gateway from helm chart" -Start $start $step++ helm install "$Path/piraeus-websocket" --namespace kube-system --set dataConnectionString="$orleansConnectionString" --set auditConnectionString="$auditConnectionString" --set clientIdentityNameClaimType="$identityClaimType" --set clientIssuer="$issuer" --set clientAudience="$audience" --set clientTokenType="$tokenType" --set clientSymmetricKey="$symmetricKey" --set coapAuthority="$coapAuthority" --set instrumentationKey=$websocketAIKey --set logLevel=$LogLevel } Update-Step -Step $step -Message "Updating the NGINX ingress controller" -Start $start $step++ Set-Ingress -Dns $Dns -Location $Location -Path "$Path/ingress.yaml" -Destination "$Path/ingress-copy.yaml" Update-Step -Step $step -Message "Write File = $File" -Start $start $step++ $config = [PSCustomObject]@{ subscription = $SubscriptionName resourceGroup = $ResourceGroupName piraeusClusterName = $ClusterName piraeusHostname = "$Dns.$Location.cloudapp.azure.com" piraeusDns = $Dns email = $Email location = $Location logLevel = $LogLevel nodeCount = $NodeCount appId = $spnAppId pwd = $spnPwd piraeusPublicIP = $IP tokenType = $tokenType symmetricKey = $symmetricKey identityClaimType = $identityClaimType coapAuthority = $coapAuthority orleansConnectionString = $orleansConnectionString orleanVmSize = $OrleansVmSize orleansAppInsights = "$Dns-silo" orleansAppInsightsKey = $siloAIKey gatewayVmSize = $GatewayVmSize auditConnectionString = $auditConnectionString gatewayAppInsights = "$Dns-websocket" gatewayAppInsightsKey = $websocketAIKey iotHubConnectionString = "" apiCodes = $apiSecurityCodes apiIssuer = $apiIssuer apiAudience = $apiAudience apiSymmetricKey = $apiSymmetricKey apiAppInsights = "$Dns-api" apiAppInsightsKey = $mgmtAIKey claimTypes = $identityClaimType claimValues = "" containerName = "maps" filename = "" tableName = "gateway" apiCode = $apiSecurityCodes.Split(";")[0] lifetimeMinutes = 525600 vrtuIP = "" vrtuVmSize = "" virtualRtuId = "" vrtuConnectionString = "" vrtuInstrumentationKey = "" tenantId = "" clientId = "" domain = "" monitorDns = "" monitorPublicIP = "" monitorInstrumentationKey = "" monitorVmSize = "" } $config | ConvertTo-Json -depth 100 | Out-File $File Write-Host "---- Piraeus Deployed -----" -ForegroundColor Cyan } function New-VrtuVnetDeploy { param([string]$Path, [string]$File, [string]$SubscriptionName, [string]$ResourceGroupName, [string]$Location, [string]$VirtualRtuId, [string]$Hostname, [string]$SymmetricKey, [string]$BlobContainerName, [string]$TableName, [string]$IoTHubName, [string]$LogLevel, [string]$StorageAcctName, [int]$LifetimeMinutes = 0, [string]$ClusterName, [int]$NodeCount, [string]$VmSize, [string]$VnetName, [string]$SubnetName, [string]$VnetPrefix, [string]$SubnetPrefix, [string]$ServiceCidr, [string]$DnsServiceIP, [string]$PodCidr, [string]$DockerBridgeIP, [string]$AppID, [string]$Password, [int]$Step, [DateTime]$StartTime) $env:AZURE_HTTP_USER_AGENT='pid-332e88b9-31d3-5070-af65-de3780ad5c8b' if($Step -eq 0) { $step = 0 } else { $step = $Step } $step++ $endTime = Get-Date $timeSpan = New-TimeSpan -Start $StartTime -End $endTime if($timeSpan.Days -lt 1) { $start = $StartTime } else { $start = $endTime } if($File.Length -eq 0) { $dateTimeString = Get-Date -Format "MM-dd-yyyyTHH-mm-ss" $File = "./vrtu-" + $dateTimeString + ".json" } if($BlobContainerName.Length -eq 0) { $BlobContainerName = "maps" } if($TableName.Length -eq 0) { $TableName = "gateway" } if($LogLevel.Length -eq 0) { $LogLevel = "Information" } if($LifetimeMinutes -eq 0) { $LifetimeMinutes = 525600 } if($NodeCount -eq 0) { $NodeCount = 1 } if($VmSize.Length -eq 0) { $VmSize = "Standard_D2s_v3" } if($VnetName.Length -eq 0) { $VnetName = "vrtu-vnet" } if($SubnetName.Length -eq 0) { $SubnetName = "vrtu-subnet" } if($VnetPrefix.Length -eq 0) { $VnetPrefix = "192.168.0.0/16" } if($SubnetPrefix.Length -eq 0) { $SubnetPrefix = "192.168.1.0/24" } if($ServiceCidr.Length -eq 0) { $ServiceCidr = "10.0.0.0/16" } if($DnsServiceIP.Length -eq 0) { $DnsServiceIP = "10.0.0.10" } if($PodCidr.Length -eq 0) { $PodCidr = "10.244.0.0/16" } if($DockerBridgeIP.Length -eq 0) { $DockerBridgeIP = "172.17.0.1/16" } #default values $claimTypes = "http://$Hostname/name" $claimValues = $VirtualRtuId $issuer = "http://$Hostname/" $audience = $issuer $filename = "$VirtualRtuId.json" Write-Host "LTM = $LifetimeMinutes" -ForegroundColor Cyan $ltm = '\"'+ $LifetimeMinutes + '\"' #get the service principal Update-Step -Step $step -Message "Set Service Principal" -Start $start $step++ $spn = Get-ServicePrincipal -AppID $AppID -Password $Password $spnAppId = $spn."appId" $spnPwd = $spn."pwd" $iotHubConnection = Get-IoTHubConnectionString -HubName "$IoTHubName" -ResourceGroupName "$ResourceGroupName" if($iotHubConnection.Length -eq 0) { Write-Host "No IoT Hub connection string...stopping script" -ForegroundColor DarkCyan return } #create the storage account $storageAvailable = Get-StorageAccountNameAvailable -SubscriptionName "$SubscriptionName" -StorageAcctName "$StorageAcctName" if($storageAvailable) { New-StorageAccount -StorageAcctName $StorageAcctName -Location $Location -ResourceGroupName $ResourceGroupName } $storageConnectionString = Get-StorageAccountConnectionString -StorageAcctName $StorageAcctName -ResourceGroupName $ResourceGroupName if($LASTEXITCODE -ne 0) { Write-Host "Failed to get VRTU storage account connection string...terminating script." -ForegroundColor Yellow return } Update-Step -Step $step -Message "VRTU storage account connection string obtained" -Start $start $step++ #create app insights and get instrumentation key Update-Step -Step $step -Message "Creating App Insights for VRTU cluster and getting instrumentation key" -Start $start $step++ $instrumentationKey = Get-InstrumentationKey "$VirtualRtuId" -ResourceGroupName $ResourceGroupName -Location $Location Update-Step -Step $step -Message "Creating new VRTU VNET" -Start $start $step++ az network vnet create --resource-group $ResourceGroupName --name $VnetName --address-prefixes 192.168.0.0/16 --subnet-name $SubnetName --subnet-prefix 192.168.1.0/24 $VnetName_ID=$(az network vnet show --resource-group $ResourceGroupName --name $VnetName --query id -o tsv) $SubnetName_ID=$(az network vnet subnet show --resource-group $ResourceGroupName --vnet-name $VnetName --name $SubnetName --query id -o tsv) Update-Step -Step $step -Message "Assigning role to service principal" -Start $start $step++ az role assignment create --assignee $spnAppId --scope $VnetName_ID --role Contributor Update-Step -Step $step -Message "Creating new VRTU AKS cluster" -Start $start $step++ az aks create --resource-group $ResourceGroupName --name $ClusterName --node-count $NodeCount --network-plugin kubenet --service-cidr $ServiceCidr --dns-service-ip $DnsServiceIP --pod-cidr $PodCidr --docker-bridge-address $DockerBridgeIP --vnet-subnet-id $SubnetName_ID --service-principal "$spnAppId" --client-secret "$spnPwd" kubectl config use-context $ClusterName Update-Step -Step $step -Message "Getting AKS credentials" -Start $start $step++ az aks get-credentials --resource-group $ResourceGroupName --name $ClusterName Update-Step -Step $step -Message "Applying Helm RBAC" -Start $start $step++ kubectl apply -f "./helm-rbac.yaml" Update-Step -Step $step -Message "Starting Tiller" -Start $start $step++ helm init --service-account tiller Set-Timer -Message "...waiting 45 seconds for Tiller to start" -Seconds 45 Update-Step -Step $step -Message "Deploying helm chart for VRTU VNET" -Start $start $step++ helm install "$Path/virtualrtu-vnet" --name virtualrtu --namespace kube-system --set claimTypes=$claimTypes --set claimValues=$claimValues --set issuer=$issuer --set audience=$audience --set lifetimeMinutes=$ltm --set symmetricKey=$SymmetricKey --set hostname=$Hostname --set storageConnectionString="$storageConnectionString" --set container=$BlobContainerName --set filename=$filename --set virtualRtuId=$VirtualRtuId --set instrumentationKey=$instrumentationKey --set logLevel=$LogLevel Write-Host "-- Step $step - Geting IP for Subnet communications" -ForegroundColor Green $ip = Get-ExternalIPForService -AppName "vrtu" $step++ Write-Host "-- IP = $ip " -ForegroundColor Magenta Update-Step -Step $step -Message "Read file" -Start $start $step++ if(Test-Path $File) { $config = Get-Content -Raw -Path $File | ConvertFrom-Json $config.claimValues = "$VirtualRtuId" $config.containerName = "$BlobContainerName" $config.filename = "$VirtualRtuId.json" $config.tableName = "$TableName" $config.lifetimeMinutes = $LifetimeMinutes $config.vrtuVmSize = "$VmSize" $config.virtualRtuId = "$VirtualRtuId" $config.vrtuConnectionString = "$storageConnectionString" $config.vrtuInstrumentationKey = "$instrumentationKey" $config.iotHubConnectionString = "$iotHubConnection" $config.vrtuIP = "$ip" Update-Step -Step $step -Message "Write file" -Start $start $step++ $config | ConvertTo-Json -depth 100 | Out-File $File } Write-Host "VRTU-VNET deployed!" -ForegroundColor Cyan } function New-WebMonitorDeploy { param([string]$Path, [string]$File, [string]$SubscriptionName, [string]$ResourceGroupName, [string]$PiraeusHostname, [string]$VirtualRtuId, [string]$StorageAcctName, [string]$SymmetricKey, [string]$Dns, [string]$Location, [string]$Email, [string]$ClusterName, [string]$Domain, [int]$Port, [string]$AppID, [string]$Password, [string]$VmSize, [string]$TableName, [int]$NodeCount, [string]$LogLevel, [int]$Step, [DateTime]$StartTime) $step = $Step $step++ $env:AZURE_HTTP_USER_AGENT='pid-332e88b9-31d3-5070-af65-de3780ad5c8b' $endTime = Get-Date $timeSpan = New-TimeSpan -Start $StartTime -End $endTime if($timeSpan.Days -lt 1) { $start = $StartTime } else { $start = $endTime } if($LogLevel.Length -eq 0) { $LogLevel = "Information" } if($VmSize.Length -eq 0) { $VmSize = "Standard_D2s_v3" } if($TableName.Length -eq 0) { $TableName = "gateway" } if($NodeCount -eq 0) { $NodeCount = 1 } Update-Step -Step $step -Message "Set Subscription for deployment" -Start $start $step++ Set-Subscription -SubscriptionName $SubscriptionName Update-Step -Step $step -Message "Set Resource Group for deployment" -Start $start $step++ Set-ResourceGroup -ResourceGroupName $ResourceGroupName -Location $Location Update-Step -Step $step -Message "Get Service Principal" -Start $start $step++ $spn = Get-ServicePrincipal -AppID $AppID -Password $Password $spnAppId = $spn."appId" $spnPwd = $spn."pwd" Update-Step -Step $step -Message "Get Tenant ID" -Start $start $step++ $tenantId = Get-TenantId -SubscriptionName "$SubscriptionName" Update-Step -Step $step -Message "Check for App Registration" -Start $start $step++ $appRegJson = az ad app list --display-name "$VirtualRtuId-Monitor" | ConvertFrom-Json if($appRegJson.Length -eq 1) { Update-Step -Step $step -Message "Deleting App Registration" -Start $start $step++ az ad app delete --id $appRegJson.appId } Update-Step -Step $step -Message "Register App in AAD and get Client Id" -Start $start $step++ $appName = "$VirtualRtuId-Monitor" $replyUris = @("https://$Dns.$Location.cloudapp.azure.com/signin-oidc","https://locahost:44386") $clientId = New-RegisterApp -AppName $appName -ReplyUris $replyUris Update-Step -Step $step -Message "Get Storage Connection String" -Start $start $step++ $vrtuConnectionString = Get-StorageAccountConnectionString -StorageAcctName "$StorageAcctName" -ResourceGroupName "$ResourceGroupName" Update-Step -Step $step -Message "See if Monitor AKS cluster exists" -Start $start $step++ $clusterExists = Get-AksClusterExists -SubscriptionName $SubscriptionName -ClusterName $ClusterName if($clusterExists) { Update-Step -Step $step -Message "Setting kubectl context to monitor cluster" -Start $start $step++ kubectl config use-context $ClusterName Update-Step -Step $step -Message "Updating ingress DNS and Location" -Start $start $step++ #Update-MonitorIngressDns -Dns $Dns -Location $Location -Path "$Path/ingress-webmonitor.yaml" -Destination "$Path/ingress-webmonitor-$Dns.yaml" Set-Ingress -Dns $Dns -Location $Location -Path "$Path/ingress-webmonitor.yaml" -Destination "$Path/ingress-webmonitor-copy.yaml" } else { kubectl create namespace "webmon" Update-Step -Step $step -Message "Creating new Monitor AKS cluster" -Start $start $step++ New-AksCluster -ClusterName $ClusterName -ResourceGroupName $ResourceGroupName -AppId "$spnAppId" -Password "$spnPwd" -VmSize $VmSize -NodeCount $NodeCount kubectl config use-context $ClusterName Update-Step -Step $step -Message "Get AKS credentials" -Start $start $step++ Get-AksCredentials -ClusterName $ClusterName -ResourceGroupName $ResourceGroupName Update-Step -Step $step -Message "Apply HELM RBAC" -Start $start $step++ New-KubectlApply -Filename "$Path/helm-rbac.yaml" -Namespace "kube-system" Update-Step -Step $step -Message "Start Tiller" -Start $start $step++ helm init --service-account tiller Set-Timer -Message "...waiting 45 seconds for Tiller to start" -Seconds 45 Update-Step -Step $step -Message "Add cert manager for Let's Encrypt" -Start $start $step++ Add-CertManager2 -Namespace "cert-manager2" Set-Timer -Message "...waiting 45 seconds for cert-manager to initialize" -Seconds 45 Update-Step -Step $step -Message "Add cert issuer for Lets Encrypt" -Start $start $step++ Add-Issuer -Email $Email -IssuerPath "$Path/issuer2.yaml" -IssuerDestination "$Path/issuer2-copy.yaml" -Namespace "webmon" Set-Timer -Message "...waiting 30 seconds for issuer to initialize" -Seconds 30 Update-Step -Step $step -Message "Upate local HELM repo" -Start $start $step++ helm repo add stable https://kubernetes-charts.storage.googleapis.com/ Update-Step -Step $step -Message "Add NGINX" -Start $start $step++ Add-NGINX -Namespace "webmon" Set-Timer "...waiting 45 seconds for nginx to initialize" -Seconds 45 Update-Step -Step $step -Message "Get External IP address" -Start $start $step++ $IP = Get-ExternalIP -Namespace "webmon" Update-Step -Step $step -Message "Create Public IP ID" -Start $start $step++ $PUBLICIPID=$(az network public-ip list --query "[?ipAddress!=null]|[?contains(ipAddress, '$IP')].[id]" --output tsv) Update-Step -Step $step -Message "Update Public IP ID" -Start $start $step++ Update-PublicIP -PublicIP $PUBLICIPID -Dns $Dns -SubscriptionName $SubscriptionName Update-Step -Step $step -Message "Set certificate for cert-manager and Lets Encrypt" -Start $start $step++ Set-Certificate -Dns $Dns -Location $Location -Path "$Path/certificate2.yaml" -Destination "$Path/certificate2-copy.yaml" -Namespace "webmon" } Update-Step -Step $step -Message "Creating App Insights for Monitor and getting instrumentation key" -Start $start $step++ $aiKey = Get-InstrumentationKey "$Dns-monitors" -ResourceGroupName $ResourceGroupName -Location $Location Update-Step -Step $step -Message "Install Web Monitor from helm chart" -Start $start $step++ $domain = "$Domain.onmicrosoft.com" $hostname = $PiraeusHostname helm install "$Path/virtualrtu-webmonitor" --name virtualrtu-webmonitor --namespace "webmon" --set port=$Port --set symmetricKey=$SymmetricKey --set instrumentationKey=$aiKey --set logLevel=$LogLevel --set tenantId=$tenantId --set clientId=$clientId --set domain=$domain --set hostname=$hostname --set location=$Location --set storageConnectionString=$vrtuConnectionString --set tableName=$TableName if($LASTEXITCODE -ne 0 ) { Update-Step -Step $step -Message "Waiting for Kubernetes API Services to start" -Start $start $step++ Set-WaitForApiServices Update-Step -Step $step -Message "Trying again to install VRTU Monitor from helm chart" -Start $start $step++ helm install "$Path/virtualrtu-webmonitor" --name virtualrtu-webmonitor --namespace "webmon" --set port=$Port --set symmetricKey=$SymmetricKey --set instrumentationKey=$aiKey --set logLevel=$LogLevel --set tenantId=$tenantId --set clientId=$clientId --set domain=$domain --set hostname=$hostname --set location=$Location --set storageConnectionString=$vrtuConnectionString --set tableName=$TableName } #Update-Step -Step $step -Message "Updating the Ingress controller Location and DNS" -Start $start #$step++ #Update-MonitorIngressDns -Dns $Dns -Location $Location -Path "$Path/ingress2.yaml" -Destination "$Path/ingress-webmonitor-$Dns.yaml" #Update-Step -Step $step -Message "Updating the Ingress controller for VRTU and Port" -Start $start #$step++ #Update-MonitorIngressController -File "$Path/ingress-webmonitor-$Dns.yaml" -VirtualRtuId $VirtualRtuId -Port $Port -Namespace "webmon" #Update-Step -Step $step -Message "Updating the Ingress controller in AKS" -Start $start #$step++ Set-Ingress -Dns $Dns -Location $Location -Path "$Path/ingress2.yaml" -Destination "$Path/ingress2-copy.yaml" -Namespace "webmon" #Set-Ingress -Dns $Dns -Location $Location -Path "$Path/ingress-webmonitor-$Dns.yaml" -Destination "$Path/ingress-webmonitor-$Dns-copy.yaml" -Namespace "webmon" #New-KubectlApply -Filename "$Path/ingress-webmonitor-$Dns.yaml" -Namespace "webmon" #New-KubectlApply -Filename "$Path/ingress-webmonitor.yaml" -Namespace "kube-system" Update-Step -Step $step -Message "Read file" -Start $start $step++ if(Test-Path $File) { $config = Get-Content -Raw -Path $File | ConvertFrom-Json $config.tenantId = "$tenantId" $config.clientId = "$clientId" $config.domain = "$domain" $config.monitorDns = "$Dns" $config.monitorPublicIP = "$IP" $config.monitorInstrumentationKey = "$aiKey" $config.monitorVmSize = "$VmSize" Update-Step -Step $step -Message "Write file" -Start $start $step++ $config | ConvertTo-Json -depth 100 | Out-File $File } } function Add-CertManager { param([string]$Namespace = "cert-manager") kubectl label namespace $Namespace certmanager.k8s.io/disable-validation="true" kubectl apply -f "https://raw.githubusercontent.com/jetstack/cert-manager/release-0.11/deploy/manifests/00-crds.yaml" -n "$Namespace" --validate=false helm repo add jetstack https://charts.jetstack.io helm repo update helm install --name cert-manager --namespace $Namespace --version v0.11.0 --set ingressShim.extraArgs='{--default-issuer-name=letsencrypt-prod,--default-issuer-kind=ClusterIssuer}' jetstack/cert-manager --set webhook.enabled=true } function Add-CertManager2 { param([string]$Namespace = "cert-manager") kubectl label namespace $Namespace certmanager.k8s.io/disable-validation="true" kubectl apply -f "https://raw.githubusercontent.com/jetstack/cert-manager/release-0.11/deploy/manifests/00-crds.yaml" -n "$Namespace" --validate=false helm repo add jetstack https://charts.jetstack.io helm repo update helm install --name cert-manager --namespace $Namespace --version v0.11.0 --set ingressShim.extraArgs='{--default-issuer-name=letsencrypt-prod,--default-issuer-kind=ClusterIssuer}' jetstack/cert-manager --set webhook.enabled=true } function Add-Issuer { param([string]$Email, [string]$IssuerPath, [string]$IssuerDestination, [string]$Namespace = "kube-system") Copy-Item -Path $IssuerPath -Destination $IssuerDestination Update-Yaml -NewValue $Email -MatchString "EMAILREF" -Filename $IssuerDestination kubectl apply -f $IssuerDestination -n $Namespace Remove-Item -Path $IssuerDestination } function Add-NGINX { param([string]$Namespace = "kube-system") $looper = $true while($looper) { try { helm install stable/nginx-ingress --namespace $Namespace --set controller.replicaCount=1 if($LASTEXITCODE -ne 0 ) { Write-Host "Error installing NGINX, waiting 20 seconds to try install NGINX again..." -ForegroundColor Yellow Start-Sleep -Seconds 20 } else { $looper = $false } } catch { Write-Host "Waiting 20 seconds to try install NGINX again..." -ForegroundColor Yellow Start-Sleep -Seconds 20 } } } function Add-NodePool() { param([string]$ResourceGroupName, [string]$ClusterName, [string]$NodePoolName, [int]$NodeCount, [string]$VmSize) az aks nodepool add --resource-group $ResourceGroupName --cluster-name $ClusterName --name $NodePoolName --node-count $NodeCount --node-vm-size $VmSize } function Add-VrtuToIngressController { param([string]$File, [string]$VirtualRtuId, [int]$Port) $append = $false $output = $null foreach($line in Get-Content "$File") { Write-Host $line if($line -contains " paths:") { $append = $true } if($append -eq $true) { $output += "$line`r`n" } } #add the new lines $output += " - path: /$VirtualRtuId`r`n" $output += " backend:`r`n" $output += " serviceName: $VirtualRtuId`r`n" $output += " servicePort: $Port`r`n" $fileOutput = $null foreach($line in Get-Content "$File") { if($line -contains " paths:") { $fileOutput += "$output`r`n" break } else { $fileOutput += "$line`r`n" } } $fileOutput >> $File } function Add-WebMonitor { param([string]$Path, [string]$SubscriptionName, [string]$ResourceGroupName, [string]$PiraeusHostname, [string]$VirtualRtuId, [string]$Dns, [string]$Location, [string]$Email, [string]$ClusterName, [string]$TenantId, [string]$Domain, [int]$Port, [string]$AppId, [string]$Password, [int]$Step = 1, [DateTime]$StartTime) $step = $Step $endTime = Get-Date $timeSpan = New-TimeSpan -Start $StartTime -End $endTime if($timeSpan.Days -lt 1) { $start = $StartTime } else { $start = $endTime } Set-Subscription -SubscriptionName $SubscriptionName Update-Step -Step $step -Message "Get Service Principal" -Start $start $step++ $spn = Get-ServicePrincipal -AppID $AppID -Password $Password $spnAppId = $spn."appId" $spnPwd = $spn."pwd" Update-Step -Step $step -Message "Register App in AAD and get Client Id" -Start $start $step++ $appName = "$VirtualRtuId-Monitor" $replayUris = @("https://$Dns.$Location.cloudapp.azure.com/signin-oidc","https://locahost:44386") $clientId = New-RegisterApp -AppName $appName -ReplyUris $replyUris Update-Step -Step $step -Message "See if Monitor AKS cluster exists" -Start $start $step++ $clusterExists = Get-AksClusterExists -SubscriptionName $SubscriptionName -ClusterName $ClusterName if($clusterExists) { Update-Step -Step $step -Message "Setting kubectl context to monitor cluster" -Start $start $step++ kubectl config use-context $ClusterName Update-MonitorIngressDns -Dns $Dns -Location $Location -Path "$Path/ingress-webmonitor.yaml" -Destination "$Path/ingress-webmonitor-$Dns.yaml" } else { Write-Host "AKS cluster does not exist...terminating" -ForegroundColor Yellow return } Update-Step -Step $step -Message "Install Web Monitor from helm chart" -Start $start $step++ $domain = "$Domain.onmicrosoft.com" $hostname = $PiraeusHostname #"$PiraeusDns.$Location.cloudapp.azure.com" helm install "$Path/virtualrtu-webmonitor" --name virtualrtu-webmonitor --namespace kube-system --set app="$VirtualRtuId-monitor" --set port=$Port --set symmetricKey=$symmetricKey --set instrumentationKey=$aiKey --set logLevel=$LogLevel --set tenantId=$TenantId --set clientId=$clientId --set domain=$domain --set hostname=$hostname --set location=$Location --set storageConnectionString=$vrtuConnectionString --set tableName="gateway" if($LASTEXITCODE -ne 0 ) { Update-Step -Step $step -Message "Waiting for Kubernetes API Services to start" -Start $start $step++ Set-WaitForApiServices Update-Step -Step $step -Message "Trying again to install VRTU Monitor from helm chart" -Start $start $step++ helm install "$Path/virtualrtu-webmonitor" --name virtualrtu-webmonitor --namespace kube-system --set app="$VirtualRtuId-monitor" --set port=$Port --set symmetricKey=$symmetricKey --set instrumentationKey=$aiKey --set logLevel=$LogLevel --set tenantId=$TenantId --set clientId=$clientId --set domain=$domain --set hostname=$hostname --set location=$Location --set storageConnectionString=$vrtuConnectionString --set tableName="gateway" } Update-Step -Step $step -Message "Updating the Ingress controller for VRTU and Port" -Start $start $step++ Update-MonitorIngressController -File "$Path/ingress-webmonitor-$Dns.yaml" -VirtualRtuId $VirtualRtuId -Port $Port Update-Step -Step $step -Message "Updating the Ingress controller in AKS" -Start $start $step++ New-KubectlApply -Filename "$Path/ingress-webmonitor-$Dns.yaml" -Namespace "kube-system" } function Get-AksClusterExists { param([string]$SubscriptionName, [string]$ClusterName) $aksList = az aks list --subscription "$SubscriptionName" | ConvertFrom-Json foreach($item in $aksList) { $id = $item.id $parts = $id.Split("/") $name = $parts[$parts.Length - 1] if($name -eq $ClusterName) { return $true } } return $false } function Get-AksCredentials() { param([string]$ResourceGroupName, [string]$ClusterName) $looper = $true while($looper) { try { az aks get-credentials --resource-group $ResourceGroupName --name $ClusterName $looper = $false } catch { Write-Host "Waiting 30 seconds to try get aks credentials again..." -ForegroundColor Yellow Start-Sleep -Seconds 30 } } } function Get-ApiServicesOnline() { $v = kubectl get apiservice $ft = $true while(([string]$v).IndexOf("False") -ne -1) { if($ft) { Write-Host("K8 metrics-server and/or cert-manager-webhook is offline right now. We'll keep waiting until they are online") -ForegroundColor Yellow $ft = $false } else { Write-Host("Waiting 60 secs for the K8 apiservices to come back online, yuck...") -ForegroundColor Yellow } Start-Sleep -Seconds 60 $v = kubectl get apiservice } } function Get-ExternalIPForService { param([string]$AppName, [string]$Namespace = "kube-system") $looper = $TRUE while($looper) { $externalIP = "" $lineValue = kubectl get service -l app=$AppName --namespace $Namespace Write-Host "Last Exit Code for get external ip $LASTEXITCODE" -ForegroundColor White if($LASTEXITCODE -ne 0 ) { Write-Host "Try get external ip...waiting 30 seconds" -ForegroundColor Yellow Start-Sleep -Seconds 30 } elseif($lineValue.Length -gt 0) { $line = $lineValue[1] $lineout = $line -split '\s+' $externalIP = $lineout[3] } if($externalIP -eq "<pending>") { Write-Host "External IP is pending...waiting 30 seconds" -ForegroundColor Yellow Start-Sleep -Seconds 30 } elseif($externalIP.Length -eq 0) { Write-Host "External IP is zero length...waiting 30 seconds" -ForegroundColor Yellow Start-Sleep -Seconds 30 } else { $looper = $FALSE Write-Host "External IP is $externalIP" -ForegroundColor Magenta return $externalIP } } } function Get-ExternalIP { param([string]$Namespace = "kube-system") $looper = $TRUE while($looper) { $externalIP = "" $lineValue = kubectl get service -l app=nginx-ingress --namespace $Namespace Write-Host "Last Exit Code for get external ip $LASTEXITCODE" -ForegroundColor White if($LASTEXITCODE -ne 0 ) { Write-Host "Try get external ip...waiting 30 seconds" -ForegroundColor Yellow Start-Sleep -Seconds 30 } elseif($lineValue.Length -gt 0) { $line = $lineValue[1] $lineout = $line -split '\s+' $externalIP = $lineout[3] } if($externalIP -eq "<pending>") { Write-Host "External IP is pending...waiting 30 seconds" -ForegroundColor Yellow Start-Sleep -Seconds 30 } elseif($externalIP.Length -eq 0) { Write-Host "External IP is zero length...waiting 30 seconds" -ForegroundColor Yellow Start-Sleep -Seconds 30 } else { $looper = $FALSE Write-Host "External IP is $externalIP" -ForegroundColor Magenta return $externalIP } } } function Get-InstrumentationKey { param([string]$AppName, [string]$ResourceGroupName, [string]$Location) $jsonAppString = az monitor app-insights component show --app $AppName -g $ResourceGroupName $host.ui.RawUI.ForegroundColor = 'Gray' if($LASTEXITCODE -ne 0) { Write-Host "Not an error. App Insights component not found and will be created." -ForegroundColor Yellow Write-Host "-- Step $step - Creating App Insights $AppName" -ForegroundColor Green $jsonAppString = az monitor app-insights component create -a $AppName -l $Location -k other -g $ResourceGroupName --application-type other $step++ } $appKey = New-RandomKey(8) $jsonKeyString = az monitor app-insights api-key create --api-key $appKey -g $ResourceGroupName -a $AppName $keyObj = ConvertFrom-Json -InputObject "$jsonKeyString" $instrumentationKey = $keyObj.apiKey $host.ui.RawUI.ForegroundColor = 'Gray' return $instrumentationKey } function Get-IoTHubConnectionString { param([string]$HubName, [string]$ResourceGroupName) $hub = az iot hub show-connection-string --name $HubName --resource-group $ResourceGroupName | ConvertFrom-Json if($LASTEXITCODE -ne 0) { $host.ui.RawUI.ForegroundColor = 'Gray' Write-Host "Not an error. The IoT Hub does not exist. Trying to create a free IoT Hub" -ForegroundColor Yellow $res = az iot hub create --name $HubName --resource-group $ResourceGroupName --sku F1 --partition-count 2 $host.ui.RawUI.ForegroundColor = 'Gray' if($LASTEXITCODE -ne 0) { $host.ui.RawUI.ForegroundColor = 'Gray' Write-Host "Not an error. Cannot create a free IoT Hub (F1) because it is already used." -ForegroundColor Yellow $newS1Sku = Read-Host "Would you like to create an S1 SKU (25/month) [y/n] ? " if($newS1Sku.ToLowerInvariant() -eq "y") { $host.ui.RawUI.ForegroundColor = 'Gray' az iot hub create --name $HubName --resource-group $ResourceGroupName --sku S1 } else { Write-Host("Exiting script") -ForegroundColor Yellow return "" } } $host.ui.RawUI.ForegroundColor = 'Gray' Write-Host "Waiting 60 seconds for IoT Hub to be available." -ForegroundColor Yellow Start-Sleep -Seconds 60 $hub = az iot hub show-connection-string --name $HubName --resource-group $ResourceGroupName | ConvertFrom-Json return $hub.connectionString } else { return $hub.connectionString } } function Get-ServicePrincipal { param([string]$AppID, [string]$Password) if($AppID -eq $null -or $AppID.Length -eq 0) { #create the service principal $creds = az ad sp create-for-rbac --skip-assignment $credsObj = ConvertFrom-Json -InputObject "$creds" $appId = $credsObj.appId $pwd = $credsObj.password } else { $appId = $AppID $pwd = $Password } $spn = [PSCustomObject]@{ appId = $appId pwd = $pwd } return $spn } function Get-StorageAccountConnectionString { param([string]$StorageAcctName, [string]$ResourceGroupName) $storageJsonString = az storage account show-connection-string --name $StorageAcctName --resource-group $ResourceGroupName $storageObj = ConvertFrom-Json -InputObject "$storageJsonString" return $storageObj.connectionString } function Get-StorageAccountNameAvailable { param([string]$StorageAcctName, [string]$SubscriptionName) $jsonString = az storage account check-name --name $StorageAcctName --subscription $SubscriptionName $jsonObj = ConvertFrom-Json -InputObject "$jsonString" return $jsonObj.nameAvailable } function Get-TenantId { param([string]$SubscriptionName) $acctObj = az account show --subscription "$SubscriptionName" | ConvertFrom-Json return $acctObj.tenantId } function New-AksCluster { param([string]$ClusterName, [string]$ResourceGroupName, [string]$AppID, [string]$Password, [string]$VmSize, [int]$NodeCount) az aks create --resource-group $ResourceGroupName --name $ClusterName --node-count $NodeCount --service-principal $AppID --client-secret $Password --node-vm-size $VmSize --generate-ssh-keys } function New-KubectlApply { param([string]$Filename, [string]$Namespace = "kube-system") $looper = $true while($looper) { kubectl apply -f $Filename -n $Namespace if($LASTEXITCODE -ne 0) { Write-Host "Waiting 30 to re-apply file..." -ForegroundColor Yellow Start-Sleep -Seconds 30 } else { $looper = $false } } } function New-KubectlClusterCleanup { param([string]$ClusterName, [string]$ResourceGroupName) #Remove previous deployments from kubectl $cleanup = Read-Host "Clean up previous kubectl deployment [y/n] ? " if($cleanup.ToLowerInvariant() -eq "y") { $cleanupClusterName = Read-Host "Enter previous cluster name [Enter blank == $ClusterName] " $cleanupResourceGroup = Read-Host "Enter previous resource group name [Enter blank == $ResourceGroupName] " if($cleanupClusterName.Length -eq 0) { $cleanupClusterName = $ClusterName } if($cleanupResourceGroup.Length -eq 0) { $cleanupResourceGroup = $ResourceGroupName } $condition1 = "users.clusterUser_" + $cleanupResourceGroup + "_" + $cleanupClusterName $condition2 = "clusters." + $cleanupClusterName kubectl config unset $condition1 kubectl config unset $condition2 } } function New-RandomKey { param([int]$Length) $random = new-Object System.Random $buffer = [System.Byte[]]::new($Length) $random.NextBytes($buffer) $stringVar = [Convert]::ToBase64String($buffer) if($stringVar.Contains("+") -or $stringVar.Contains("/")) { return New-RandomKey($Length) } else { return $stringVar } } function New-RandomStorageAcctName() { $alpha = "abcdefghijklmnopqrstuvwxyz" $alpha2 = "0123456789" $array = $alpha.ToCharArray() $array2 = $alpha2.ToCharArray() $maxLength = 6 $random = new-Object System.Random $randonString = "" $dummy = $null For ($i=0; $i -lt $maxLength; $i++) { $index = $random.Next($alpha.Length) $randomString += $array[$index] } $maxLength = 2 For ($i=0; $i -lt $maxLength; $i++) { $index = $random.Next($alpha2.Length) $randomString += $array2[$index] } return $randomString } function New-RegisterApp { param([string]$AppName, $ReplyUris) $adObj = az ad app list --filter "displayName eq '$AppName'" | ConvertFrom-Json if($adObj.appId.Length -ne 0) { return $adObj.appId } else { $regObj = az ad app create --display-name "$AppName" --native-app $false --reply-urls $ReplyUris | ConvertFrom-Json return $regObj.appId } } function New-SampleConfig() { param([string]$DnsName, [string]$Location, [string]$Key) $authority = $DnsName.ToLower() + "." + $Location.ToLower() + ".cloudapp.azure.com" $url = "https://$authority" Write-Host "Using $url for management api" -ForegroundColor Yellow Import-Module "../src/Piraeus.Module.Core/bin/Release/netcoreapp3.0/Piraeus.Module.Core.dll" Write-Host "Module imported" -ForegroundColor Yellow #get a security token for the management API Write-Host "--- Get security token for Piraeus configuration ---" -Foreground Yellow $token = Get-PiraeusManagementToken -ServiceUrl $url -Key $Key while($LASTEXITCODE -ne 0) { Write-Host "--- Try get security token again...waiting 30 seconds" -ForegroundColor Yellow Start-Sleep -Seconds 30 $token = Get-PiraeusManagementToken -ServiceUrl $url -Key $Key } Write-Host "--- Got security token, ready to configure Piraeus ---" -ForegroundColor Green Write-Host "--- INFORMATION ABOUT Sample Config ----" -ForegroundColor White Write-Host "The client demos create security tokens based on the selection of a 'Role', i.e., 'A' or 'B'" -ForegroundColor White Write-Host "The script will create 2 CAPL policies" -ForegroundColor White Write-Host " (1) a client in role 'A' may transmit to 'resource-a' and subscribe to 'resource-b'" -ForegroundColor White Write-Host " (2) a client in role 'B' may transmit to 'resource-b' and subscribe to 'resource-a'" -ForegroundColor White Write-Host "-----------------------------------------" -ForegroundColor White Write-Host "" Start-Sleep -Seconds 1 #--------------- CAPL policy for users in role "A" ------------------------ Write-Host "-- Building CAPL Authorization Policies ---" -ForegroundColor White Write-Host " (1) Match Expression : Find a claim type in the security token" -ForegroundColor White Write-Host " (2) Operation -- Binds a claim value from the matched claim type to perform an operation, e.g., Equals" -ForegroundColor White Write-Host " (3) Rule -- Create a rule that binds a match expression and an operation" -ForegroundColor White Write-Host " (4) Policy -- create a policy that is uniquely identifiable, that incorporates a Rule (or Logical Connective)" -ForegroundColor White Write-Host "" Start-Sleep -Seconds 1 #define the claim type to match to determines the client's role $authority = $DnsName.ToLower() + "." + $Location.ToLower() + "." + "cloudapp.azure.com" $matchClaimType = "http://$authority/role" #create a match expression of 'Literal' to match the role claim type $match = New-CaplMatch -Type Literal -ClaimType $matchClaimType -Required $true #create an operation to check the match claim value is 'Equal' to "A" $operation_A = New-CaplOperation -Type Equal -Value "A" #create a rule to bind the match expression and operation $rule_A = New-CaplRule -Evaluates $true -MatchExpression $match -Operation $operation_A #define a unique identifier (as URI) for the policy $policyId_A = "http://$authority/policy/resource-a" #create the policy for clients in role "A" $policy_A = New-CaplPolicy -PolicyID $policyId_A -EvaluationExpression $rule_A #-------------------End Policy for "B"------------------------------------ #--------------- CAPL policy for users in role "B" ------------------------ #create an operation to check the match claim value is 'Equal' to "B" $operation_B = New-CaplOperation -Type Equal -Value "B" #create a rule to bind the match expression and operation $rule_B = New-CaplRule -Evaluates $true -MatchExpression $match -Operation $operation_B #define a unique identifier (as URI) for the policy $policyId_B = "http://$authority/policy/resource-b" #create the policy for users in role "A" $policy_B = New-CaplPolicy -PolicyID $policyId_B -EvaluationExpression $rule_B #-------------------End Policy for "B"------------------------------------ # The policies are completed. We need to add them to Piraeus Add-CaplPolicy -ServiceUrl $url -SecurityToken $token -Policy $policy_A Add-CaplPolicy -ServiceUrl $url -SecurityToken $token -Policy $policy_B Write-Host "CAPL policies added to Piraeus" -ForegroundColor Yellow #Uniquely identify Piraeus resources by URI $resource_A = "http://$authority/resource-a" $resource_B = "http://$authority/resource-b" #Add the resources to Piraeus #Resource "A" lets users with role "A" send and users with role "B" subscribe to receive transmissions Add-PiraeusEventMetadata -ResourceUriString $resource_A -Enabled $true -RequireEncryptedChannel $false -PublishPolicyUriString $policyId_A -SubscribePolicyUriString $policyId_B -ServiceUrl $url -SecurityToken $token -Audit $false #Resource "B" lets users with role "B" send and users with role "A" subscribe to receive transmissions Add-PiraeusEventMetadata -ResourceUriString $resource_B -Enabled $true -RequireEncryptedChannel $false -PublishPolicyUriString $policyId_B -SubscribePolicyUriString $policyId_A -ServiceUrl $url -SecurityToken $token -Audit $false Write-Host "PI-System metadata added to Piraeus" -ForegroundColor Yellow Write-Host"" #Quick check get the resource data and verify what was set Write-Host "----- PI-System $resource_A Metadata ----" -ForegroundColor Green Get-PiraeusEventMetadata -ResourceUriString $resource_A -ServiceUrl $url -SecurityToken $token Write-Host"" Write-Host "----- PI-System $resource_B Metadata ----" -ForegroundColor Green Get-PiraeusEventMetadata -ResourceUriString $resource_B -ServiceUrl $url -SecurityToken $token } function New-StorageAccount { param([string]$StorageAcctName, [string]$Location, [string]$ResourceGroupName) az storage account create --location $Location --name $StorageAcctName --resource-group $ResourceGroupName --sku "Standard_LRS" --kind StorageV2 } function Remove-AksCluster() { param([string]$ClusterName, [string]$ResourceGroupName) $clusterLine = az aks list --query "[?contains(name, '$ClusterName')]" --output table if($clusterLine.Length -gt 0) { az aks delete --name $ClusterName --resource-group $ResourceGroupName --yes } } function Set-AppInsightsExtension() { az extension show -n application-insights if($LASTEXITCODE -ne 0) { az extension add -n application-insights -y } } function Set-ApplyYaml { param([string]$File, [string]$Namespace) $looper = $true while($looper) { kubectl apply -f $File -n $Namespace if($LASTEXITCODE -ne 0) { Write-Host "kubectl apply failed for $File. Waiting 10 seconds to try again..." -ForegroundColor Yellow Start-Sleep -Seconds 10 } else { $looper = $false } } } function Set-Certificate { param([string]$Dns, [string]$Location, [string]$Path, [string]$Destination, [string]$Namespace = "cert-manager") Copy-Item -Path $Path -Destination $Destination Update-Yaml -NewValue $Dns -MatchString "INGRESSDNS" -Filename $Destination Update-Yaml -NewValue $Location -MatchString "LOCATION" -Filename $Destination New-KubectlApply -Filename $Destination -Namespace $Namespace Remove-Item -Path $Destination } function Set-CleanOrleansStorageAccount { param([string]$StorageAcctName) az storage container delete --name grainstate --account-name $StorageAcctName az storage table delete --name OrleansSiloInstances --account-name $StorageAcctName az storage table delete --name 'MetricsHourPrimaryTransactionsBlob' --account-name $StorageAcctName az storage table delete --name 'MetricsHourPrimaryTransactionsFile' --account-name $StorageAcctName az storage table delete --name 'MetricsHourPrimaryTransactionsQueue' --account-name $StorageAcctName az storage table delete --name 'MetricsHourPrimaryTransactionsTable' --account-name $StorageAcctName } function Set-Ingress { param([string]$Dns, [string]$Location, [string]$Path, [string]$Destination, [string]$Namespace = "kube-system") Copy-Item -Path $Path -Destination $Destination Update-Yaml -NewValue $Dns -matchString "INGRESSDNS" -filename $Destination Update-Yaml -newValue $Location -matchString "LOCATION" -filename $Destination New-KubectlApply -Filename $Destination -Namespace $Namespace Remove-Item -Path $Destination } function Set-IoTHubExtension() { az extension show -n azure-cli-iot-ext if($LASTEXITCODE -ne 0) { az extension add -n azure-cli-iot-ext -y } } function Set-NodeLabel { param([string]$NodeMatchValue, [string]$Key, [string]$Value) $looper = $true while($looper) { $nodes = kubectl get nodes if($LASTEXITCODE -ne 0) { Write-Host "Waiting 10 seconds to get nodes from kubectl..." -ForegroundColor Yellow Start-Sleep -Seconds 10 } else { foreach($node in $nodes) { $nodeVal = $node.Split(" ")[0] if($nodeVal.Contains($NodeMatchValue)) { kubectl label nodes $nodeVal "$Key=$Value" if($LASTEXITCODE -ne 0) { Write-Host "Set node label failed. Waiting 10 seconds to try again..." -ForegroundColor Yellow Start-Sleep -Seconds 10 } else { $looper = $false } } } } } } function Set-ResourceGroup { param([string]$ResourceGroupName, [string]$Location) $rgoutcome = az group exists --name $ResourceGroupName if($rgoutcome -eq "false") { az group create --name $ResourceGroupName --location $Location } } function Set-Subscription { param([string]$SubscriptionName) az account set --subscription "$SubscriptionName" } function Set-Timer { param([string]$Message, [int]$Seconds) Write-Host $Message -ForegroundColor Yellow Start-Sleep -Seconds $Seconds } function Set-WaitForApiServices() { $v = kubectl get apiservice $ft = $true while(([string]$v).IndexOf("False") -ne -1) { if($ft) { Write-Host("K8 metrics-server and/or cert-manager-webhook is offline right now. We'll keep waiting until they are online") -ForegroundColor Yellow $ft = $false } else { Write-Host("Waiting 60 secs for the K8 apiservices to come back online, yuck...") -ForegroundColor Yellow } Start-Sleep -Seconds 60 $v = kubectl get apiservice } } function Update-MonitorIngressController { param([string]$File, [string]$VirtualRtuId, [int]$Port) $fout = $null $append = $false $output = $null foreach($line in Get-Content "$File") { $fout += "$line`r`n" if($line -contains " paths:") { $fout += " - path: /$VirtualRtuId`r`n" $fout += " backend:`r`n" $fout += " serviceName: $VirtualRtuId`r`n" $fout += " servicePort: $Port`r`n" } } Set-Content -Path "$File" -Value $fout } function Update-MonitorIngressDns { param([string]$Dns, [string]$Location, [string]$Path, [string]$Destination) Copy-Item -Path $Path -Destination $Destination Update-Yaml -NewValue $Dns -matchString "INGRESSDNS" -filename $Destination Update-Yaml -newValue $Location -matchString "LOCATION" -filename $Destination } function Update-PublicIP { param([string]$PublicIP, [string]$Dns, [string]$SubscriptionName) if($subscriptionNameOrId.Length -ne 0) { az network public-ip update --ids $PublicIP --dns-name $Dns --subscription $SubscriptionName } else { az network public-ip update --ids $PublicIP --dns-name $Dns } } function Update-Step { param([int]$Step, [string]$Message, [DateTime]$Start) $endTime = Get-Date $timeSpan = New-TimeSpan -Start $Start -End $endTime $val = $timeSpan.ToString("mm\:ss") Write-Host "--Step $Step - $Message - $val" -ForegroundColor Green } function Update-Yaml() { Param ([string]$NewValue, [string]$MatchString, [string]$Filename) (Get-Content $Filename) -replace $MatchString,$NewValue | out-file $Filename -Encoding ascii } function New-DeviceDeploy { param ([string]$File, [string]$Url = "http://localhost:7071/api/DeploymentFunction", [string]$Key = $null, [bool]$Update = $false) $config = [System.IO.File]::ReadAllBytes($File) $requestUrl = $null if($Key -eq $null) { if($Update -eq $false) { $requestUrl = $Url } else { $requestUrl = $Url + "?type=update" } } else { $requestUrl = $Url + "?code=" + $Key if($Update -ne $false) { $requestUrl = $requestUrl + "&type=update" } } if($Module -eq $null) { $connectionString = Invoke-WebRequest -Uri $requestUrl -Method Post -ContentType "application/json" -Body $config Write-Host $connectionString } else { Invoke-WebRequest -Uri $requestUrl -Method Post -ContentType "application/json" -Body $config Write-Host "Update complete" } } |