SkunkLabVirtualRtu.psm1

function New-FullVrtuDeploy
{
    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-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    
    }  

}